我正在尝试使用sqlserver xquery语法重新格式化sql xml列中的值。
对于每个流派标记,我希望“G”以字符串形式写入, 内部类型取决于图书的“标记”_“如果absend或”。如果可用,没有考虑到价值。 输出字符串必须与xml完全相同。
这是我输入的xml
<Lib>
<Genre name=Horror>
<Book>
<Title>1</Title>
</Book>
<Book>
<Title>2</Title>
<Lost>1</Lost>
</Book>
<Book>
<Title>3</Title>
</Book>
</Genre>
<Genre name=Romance>
<Book>
<Title>5</Title>
</Book>
<Book>
<Title>6</Title>
<Lost>0</Lost>
</Book>
</Genre>
</Lib>
我想要实现的输出是:
G_._G_.
答案 0 :(得分:2)
一种解决方案是循环播放流派和书籍以构建结果:
for $genre in //Genre
return (
"G",
for $book in $genre/Book
return (
if ($book/Lost)
then "."
else "_"
)
)
由于您需要按文档顺序返回字母,您可以选择循环遍历所有节点,采用类似sax的方法:
for $node in //*
return (
"G"[$node/self::Genre],
"."[$node/self::Book[Lost]],
"_"[$node/self::Book[not(Lost)]]
)
请记住,节点序列的序列化是依赖于实现的,如果有任何不需要的空格,可能会有一个省略它的选项。或者,将其包装到string-join($sequence, '')
。
答案 1 :(得分:1)
首先,您无法摆脱SQL Server中格式错误的XML。
部分<Genre name=Horror>
不完整,您必须写<Genre name="Horror">
见:
DECLARE @lib xml =
'<Lib>
<Genre name="Horror">
<Book>
<Title>1</Title>
</Book>
<Book>
<Title>2</Title>
<Lost>1</Lost>
</Book>
<Book>
<Title>3</Title>
</Book>
</Genre>
<Genre name="Romance">
<Book>
<Title>5</Title>
</Book>
<Book>
<Title>6</Title>
<Lost>0</Lost>
</Book>
</Genre>
</Lib>'
如果省略引号,将返回错误。
另一件事是,这可能是应用程序逻辑的工作。但是,如果您没有应用程序层,并且您需要这个...报告(?),那么您可以使用以下代码。请注意此处使用@lib
变量。
DECLARE @output nvarchar(max)
;WITH numberedBook AS (
SELECT
GenreName,
RowNumber = ROW_NUMBER() OVER(PARTITION BY GenreName ORDER BY (SELECT NULL)),
BookTitle,
BookLost
FROM
@lib.nodes('Lib/Genre/Book') T(c)
CROSS APPLY(
SELECT
GenreName = T.c.value('../@name', 'nvarchar(255)'),
BookTitle = T.c.value('./Title[1]', 'nvarchar(255)'),
BookLost = T.c.value('./Lost[1]', 'nvarchar(255)')
) lib
)
SELECT @output =
COALESCE(@output + '', '') +
CASE WHEN RowNumber = 1 THEN 'G' ELSE '' END +
CASE WHEN BookLost IS NULL THEN '_' ELSE '.' END
FROM numberedBook
SELECT @output