T*******x 发帖数: 8565 | 1 对于一个xml的column/variable,example如下:
declare @x xml = '
hello
world
';
问题:
Find all types of containers that "immediately" contains the "inteterested"
elements.
对于这个例子,答案应该是C和D。
解释一下这个问题:
container element是一个通用element,可以嵌套,相当于树的节点。每一个
container element都有type。感兴趣的element是 element。我们想要知
道有哪里container中含有感兴趣的element。但是因为container是可以嵌套的,我们
不要最外层的那个container,只要那种“直接”包含感兴趣的element的那种
container。所谓“直接”包含是指,container和感兴趣的element之间不能有别的
container层次,但可以有其他层次。
这个问题目标数据库是SQL Server。要用SQL Server XQuery。
下面这个简单的query给出的答案不对,给出的是(A,A,C,D)。
这是一个开头。
with temp as (select @x col)
select
c.cref.value('@type', 'varchar') container_type
, cref.query('.') cxml
, xref.query('.') xxml
from temp
cross apply col.nodes('//container') c(cref)
cross apply c.cref.nodes('.//interested') x(xref) |
T*******x 发帖数: 8565 | 2 这个题真不简单。xquery我也没怎么学过。在sql server 里面用到一点基本的。这两
天看了一下,内容很丰富啊。能干的事情不少。
不过sql server对xquery的实现还是不完整的。当然也能干很多事情了。不过恰好这个
事情做不了。这个问题首先很容易定位interested elements。然后往上找ancestor,
找到最近的container,就是我们要找的答案。但是sql server对xquery的实现恰恰没
有ancestor这个函数,也就是parent, parent's parent, 等等。其他常用几个函数就
有,比如找descendant,这个正是ancestor的反面。不过ancestor是个不常用的功能,
没有实现也可以理解。
所以往上找ancestor这个功能只能借助于child往下找这个功能实现。因为container到
interested之间的层级次数不固定,必须要用到递归。
下面这个sql有点复杂,有很大可改进余地。其中一步把xml cast成string,因为xml
数据类型不能比较,不能作为join的column。不得已为之。而且有一个assumption,就
是一个xml和另一个xml如果相等,那么cast成string之后也是相等的。也就是假定xml
有一个“正则”方法cast成string。
总体思路也不复杂:
1. 先找出xml所有的node。
2. 把node和child的关系做一个列表。
3. node和child的xml都cast成string,用于后面的自join。
4. CTE ancestor是一个递归CTE,以interested element作为anchor,每一行列出一个
parent,给一个parent level。
5. 然后找出parent里面是container element的level最小的一个。
【在 T*******x 的大作中提到】 : 对于一个xml的column/variable,example如下: : declare @x xml = ' : : : : : : : hello :
|
T*******x 发帖数: 8565 | 3 奇怪,又不能贴代码了。有时候可以有时候不行。
【在 T*******x 的大作中提到】 : 这个题真不简单。xquery我也没怎么学过。在sql server 里面用到一点基本的。这两 : 天看了一下,内容很丰富啊。能干的事情不少。 : 不过sql server对xquery的实现还是不完整的。当然也能干很多事情了。不过恰好这个 : 事情做不了。这个问题首先很容易定位interested elements。然后往上找ancestor, : 找到最近的container,就是我们要找的答案。但是sql server对xquery的实现恰恰没 : 有ancestor这个函数,也就是parent, parent's parent, 等等。其他常用几个函数就 : 有,比如找descendant,这个正是ancestor的反面。不过ancestor是个不常用的功能, : 没有实现也可以理解。 : 所以往上找ancestor这个功能只能借助于child往下找这个功能实现。因为container到 : interested之间的层级次数不固定,必须要用到递归。
|
T*******x 发帖数: 8565 | 4
【在 T*******x 的大作中提到】 : 这个题真不简单。xquery我也没怎么学过。在sql server 里面用到一点基本的。这两 : 天看了一下,内容很丰富啊。能干的事情不少。 : 不过sql server对xquery的实现还是不完整的。当然也能干很多事情了。不过恰好这个 : 事情做不了。这个问题首先很容易定位interested elements。然后往上找ancestor, : 找到最近的container,就是我们要找的答案。但是sql server对xquery的实现恰恰没 : 有ancestor这个函数,也就是parent, parent's parent, 等等。其他常用几个函数就 : 有,比如找descendant,这个正是ancestor的反面。不过ancestor是个不常用的功能, : 没有实现也可以理解。 : 所以往上找ancestor这个功能只能借助于child往下找这个功能实现。因为container到 : interested之间的层级次数不固定,必须要用到递归。
|
T*******x 发帖数: 8565 | 5 再来一个版本。代码更紧凑,更烧脑。但是作为玩嘛,可能也更有意思一点。
xml cast成string之后又hash了一下,这样应该storage占用小一点吧。
ancestor recursive CTE有点不好读了:anchor还在,这个必须有。child和parent(
node)之间,只需要parent(node),一级parent,二级parent,也就是ancestor,所以
字段名字改了,就叫ancestor,和cte同名。:)
然后recursive union的base,直接加cross apply,找interested elements。上面的
部分,不找ancestor的全部了,找到parent等于第一个为止,也就是以
child不等于为条件。呵呵。有点烧脑,也有点意思。还用了一个xquery的
local-name函数,是我这两天学习xquery的成果。:)
xml之间的比较(join)还是有问题,包括cast成string或者hash,都还是有问题:因为
xml的两个不同element可以完全相等,仅靠位置(context)识别。
【在 T*******x 的大作中提到】
|