用于选择和分组的 XQuery
XQuery for selecting and grouping
我正在尝试从 xml 列中导出一些信息。
应用的逻辑:
在每个部分中,演员姓名可能会出现两次。
(演员 + 歌曲) 结果是一个独特的组合。
仅在聚合级别,场景=1 时保留。我们不关心 scene=2。
我们关心特定演员的台词。
辛巴、木法沙和沙祖。
我们不用担心疤痕。他很卑鄙。
我的预期输出是:
output
到目前为止我的 T-Sql 代码:
我已经设法过滤掉聚合级别 = 2.
有人可以帮忙吗?
DECLARE @Temp AS TABLE (Information xml)
INSERT INTO @Temp SELECT @x;
WITH XMLNAMESPACES ('lyceum' AS ns1)
SELECT
Z.query('ns1:feature')
FROM @Temp
CROSS APPLY Information.nodes('/ns1:report/ns1:detail/ns1:parts/ns1:part') AS Y(Z)
WHERE Z.exist('ns1:aggregation[.="1"]') = 1
您可以在下面找到 xml 以便轻松重现:
DECLARE @x as xml;
set @x = '<ns1:report xmlns:ns1="lyceum">
<ns1:header>
<ns1:report>The Lion King</ns1:report>
</ns1:header>
<ns1:detail>
<ns1:parts>
<ns1:part>
<ns1:aggregation>
<ns1:scene>1</ns1:scene>
</ns1:aggregation>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>100</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Mufasa</ns1:actor>
<ns1:lines>200</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>300</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Zazu</ns1:actor>
<ns1:lines>400</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Scar</ns1:actor>
<ns1:lines>500</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
</ns1:part>
<ns1:part>
<ns1:aggregation>
<ns1:scene>2</ns1:scene>
</ns1:aggregation>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>600</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Mufasa</ns1:actor>
<ns1:lines>700</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>800</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Zazu</ns1:actor>
<ns1:lines>900</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Scar</ns1:actor>
<ns1:lines>1000</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
</ns1:part>
</ns1:parts>
</ns1:detail>
</ns1:report>'
您正在向 select 和组请求 XQuery:试试这个:
一个模型table来模拟您的问题:
DECLARE @Temp AS TABLE (Information xml);
INSERT @Temp VALUES
('<ns1:report xmlns:ns1="lyceum">
<ns1:header>
<ns1:report>The Lion King</ns1:report>
</ns1:header>
<ns1:detail>
<ns1:parts>
<ns1:part>
<ns1:aggregation>
<ns1:scene>1</ns1:scene>
</ns1:aggregation>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>100</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Mufasa</ns1:actor>
<ns1:lines>200</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>300</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Zazu</ns1:actor>
<ns1:lines>400</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Scar</ns1:actor>
<ns1:lines>500</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
</ns1:part>
<ns1:part>
<ns1:aggregation>
<ns1:scene>2</ns1:scene>
</ns1:aggregation>
<ns1:feature>
<!-- shortened for brevity -->
</ns1:feature>
</ns1:part>
</ns1:parts>
</ns1:detail>
</ns1:report>');
--查询
WITH XMLNAMESPACES('lyceum' AS ns1)
SELECT p.query('<root>
{
for $s in distinct-values(ns1:feature/ns1:song/text())
return <song scene="{$s}">
{
for $f in ns1:feature[ns1:song[text()=$s]]
return
if($f/ns1:actor/text() != "Scar") then
<actor name="{$f/ns1:actor/text()}" lines="{$f/ns1:lines/text()}"/>
else
()
}
</song>
}
</root>')
FROM @Temp t
CROSS APPLY t.Information.nodes('/ns1:report/ns1:detail/ns1:parts/ns1:part[(ns1:aggregation/ns1:scene/text())[1]="1"]') A(p);
结果
<root>
<song scene="1">
<actor name="Simba" lines="100" />
<actor name="Mufasa" lines="200" />
</song>
<song scene="2">
<actor name="Simba" lines="300" />
<actor name="Zazu" lines="400" />
</song>
</root>
简而言之:
- 我们将
.nodes()
中的谓词用于 return <scene>
=1 的部分
- 我们使用
.query()
来return一个新创建的XML
- 我们添加(可能省略)一个
<root>
节点
- 我们通过不同的歌曲 ID 列表添加 FLWOR 查询运行
- 我们在另一个 FLOWR 查询中使用此歌曲 ID 作为谓词来过滤拟合
<feature>
元素
- 我们检查演员的名字是否不是“Scar”
您要求的输出是一个完全不同的问题。
使用 content 作为列名需要提前知道所有预期名称(PIVOT
或 条件聚合 )或使用动态创建的语句.
我正在尝试从 xml 列中导出一些信息。
应用的逻辑: 在每个部分中,演员姓名可能会出现两次。 (演员 + 歌曲) 结果是一个独特的组合。
仅在聚合级别,场景=1 时保留。我们不关心 scene=2。 我们关心特定演员的台词。 辛巴、木法沙和沙祖。 我们不用担心疤痕。他很卑鄙。 我的预期输出是:
output
到目前为止我的 T-Sql 代码: 我已经设法过滤掉聚合级别 = 2.
有人可以帮忙吗?
DECLARE @Temp AS TABLE (Information xml)
INSERT INTO @Temp SELECT @x;
WITH XMLNAMESPACES ('lyceum' AS ns1)
SELECT
Z.query('ns1:feature')
FROM @Temp
CROSS APPLY Information.nodes('/ns1:report/ns1:detail/ns1:parts/ns1:part') AS Y(Z)
WHERE Z.exist('ns1:aggregation[.="1"]') = 1
您可以在下面找到 xml 以便轻松重现:
DECLARE @x as xml;
set @x = '<ns1:report xmlns:ns1="lyceum">
<ns1:header>
<ns1:report>The Lion King</ns1:report>
</ns1:header>
<ns1:detail>
<ns1:parts>
<ns1:part>
<ns1:aggregation>
<ns1:scene>1</ns1:scene>
</ns1:aggregation>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>100</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Mufasa</ns1:actor>
<ns1:lines>200</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>300</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Zazu</ns1:actor>
<ns1:lines>400</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Scar</ns1:actor>
<ns1:lines>500</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
</ns1:part>
<ns1:part>
<ns1:aggregation>
<ns1:scene>2</ns1:scene>
</ns1:aggregation>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>600</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Mufasa</ns1:actor>
<ns1:lines>700</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>800</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Zazu</ns1:actor>
<ns1:lines>900</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Scar</ns1:actor>
<ns1:lines>1000</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
</ns1:part>
</ns1:parts>
</ns1:detail>
</ns1:report>'
您正在向 select 和组请求 XQuery:试试这个:
一个模型table来模拟您的问题:
DECLARE @Temp AS TABLE (Information xml);
INSERT @Temp VALUES
('<ns1:report xmlns:ns1="lyceum">
<ns1:header>
<ns1:report>The Lion King</ns1:report>
</ns1:header>
<ns1:detail>
<ns1:parts>
<ns1:part>
<ns1:aggregation>
<ns1:scene>1</ns1:scene>
</ns1:aggregation>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>100</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Mufasa</ns1:actor>
<ns1:lines>200</ns1:lines>
<ns1:song>1</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Simba</ns1:actor>
<ns1:lines>300</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Zazu</ns1:actor>
<ns1:lines>400</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
<ns1:feature>
<ns1:actor>Scar</ns1:actor>
<ns1:lines>500</ns1:lines>
<ns1:song>2</ns1:song>
</ns1:feature>
</ns1:part>
<ns1:part>
<ns1:aggregation>
<ns1:scene>2</ns1:scene>
</ns1:aggregation>
<ns1:feature>
<!-- shortened for brevity -->
</ns1:feature>
</ns1:part>
</ns1:parts>
</ns1:detail>
</ns1:report>');
--查询
WITH XMLNAMESPACES('lyceum' AS ns1)
SELECT p.query('<root>
{
for $s in distinct-values(ns1:feature/ns1:song/text())
return <song scene="{$s}">
{
for $f in ns1:feature[ns1:song[text()=$s]]
return
if($f/ns1:actor/text() != "Scar") then
<actor name="{$f/ns1:actor/text()}" lines="{$f/ns1:lines/text()}"/>
else
()
}
</song>
}
</root>')
FROM @Temp t
CROSS APPLY t.Information.nodes('/ns1:report/ns1:detail/ns1:parts/ns1:part[(ns1:aggregation/ns1:scene/text())[1]="1"]') A(p);
结果
<root>
<song scene="1">
<actor name="Simba" lines="100" />
<actor name="Mufasa" lines="200" />
</song>
<song scene="2">
<actor name="Simba" lines="300" />
<actor name="Zazu" lines="400" />
</song>
</root>
简而言之:
- 我们将
.nodes()
中的谓词用于 return<scene>
=1 的部分
- 我们使用
.query()
来return一个新创建的XML - 我们添加(可能省略)一个
<root>
节点 - 我们通过不同的歌曲 ID 列表添加 FLWOR 查询运行
- 我们在另一个 FLOWR 查询中使用此歌曲 ID 作为谓词来过滤拟合
<feature>
元素 - 我们检查演员的名字是否不是“Scar”
您要求的输出是一个完全不同的问题。
使用 content 作为列名需要提前知道所有预期名称(PIVOT
或 条件聚合 )或使用动态创建的语句.