没有记录元素的XML需要在SQL Server中使用T-SQL转换为表。
DECLARE @X XML = '<ROOT>
<RECORD>
<ID>1</ID>
<AppCode>Code 1</AppCode>
<ID>2</ID>
<AppCode>Code 2</AppCode>
<ID>3</ID>
<AppCode>Code 3</AppCode>
<ID>4</ID>
<AppCode>Code 4</AppCode>
<ID>5</ID>
<AppCode>Code 5</AppCode>
</RECORD>
</ROOT>'
我尝试过这样
SELECT
CASE WHEN items.item.value('local-name(.)', 'varchar(300)') = 'ID'
THEN items.item.value('text()[1]', 'varchar(300)')
END AS ID,
CASE WHEN items.item.value('local-name(.)', 'varchar(300)') = 'AppCode'
THEN items.item.value('text()[1]', 'varchar(300)')
END AS AppCode
FROM
@X.nodes('/ROOT/record/*') AS items(item)
结果不正确-
ID AppCode
-----------------
1 NULL
NULL Code 1
2 NULL
NULL Code 2
我需要这样的结果:
ID Appcode
---------------
1 Code 1
2 Code 2
3 Code 3
4 Code 4
5 Code 5
答案 0 :(得分:0)
假设这是您要使用的格式:
ID Appcode
---------------
1 Code 1
2 Code 2
这就是我要做的:
DECLARE @X XML = '
<ROOT>
<RECORD>
<ID>1</ID>
<AppCode>Code 1</AppCode>
<ID>2</ID>
<AppCode>Code 2</AppCode>
</RECORD>
</ROOT>';
SELECT V.ID,AppCode
FROM @X.nodes('/ROOT/RECORD') AS X(R)
CROSS APPLY (VALUES(X.R.value('(./ID/text())[1]','int'),X.R.value('(./AppCode/text())[1]','varchar(10)')),
(X.R.value('(./ID/text())[2]','int'),X.R.value('(./AppCode/text())[2]','varchar(10)'))) V(ID,AppCode)
但是,这不会扩展。因此,如果您的ID为3、4,就不会给您更多的行。
答案 1 :(得分:0)
如果您可以修改XML格式并按照以下说明使用查询来获取结果
DECLARE @X XML = '<ROOT>
<RECORD>
<ID>1</ID>
<AppCode>Code 1</AppCode>
</RECORD>
<RECORD>
<ID>2</ID>
<AppCode>Code 2</AppCode>
</RECORD>
<RECORD>
<ID>3</ID>
<AppCode>Code 3</AppCode>
</RECORD>
<RECORD>
<ID>4</ID>
<AppCode>Code 4</AppCode>
</RECORD>
<RECORD>
<ID>5</ID>
<AppCode>Code 5</AppCode>
</RECORD>
</ROOT>'
DECLARE @doc int
EXEC sp_xml_preparedocument @doc OUTPUT, @X
SELECT ID, AppCode
FROM OPENXML(@doc,'/ROOT/RECORD',2)
WITH (
ID int,
AppCode varchar(10)
)
输出会喜欢
ID AppCode
1 Code 1
2 Code 2
3 Code 3
4 Code 4
5 Code 5
答案 2 :(得分:0)
尝试一下
WITH Numbers AS
(SELECT TOP(@X.value('count(//ID)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Nmbr FROM master..spt_values)
SELECT Nmbr
,@X.value('(//ID[sql:column("Nmbr")])[1]','int') AS ID
,@X.value('(//AppCode[sql:column("Nmbr")])[1]','nvarchar(max)') AS AppCode
,@X.value('(//SomeMore[sql:column("Nmbr")])[1]','nvarchar(max)') AS SomeMore
FROM Numbers;
想法
这应该可以很快地处理许多列:
DECLARE @X XML = '<ROOT>
<RECORD>
<ID>1</ID>
<AppCode>Code 1</AppCode>
<ID>2</ID>
<AppCode>Code 2</AppCode>
<ID>3</ID>
<AppCode>Code 3</AppCode>
<ID>4</ID>
<AppCode>Code 4</AppCode>
<ID>5</ID>
<AppCode>Code 5</AppCode>
</RECORD>
</ROOT>';
WITH allIDs AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Pos
,id.value('text()[1]','int') AS ID
FROM @X.nodes('/ROOT/RECORD/ID') A(id)
)
SELECT ai.Pos
,ai.ID
,@X.value('/ROOT[1]/RECORD[1]/AppCode[sql:column("ai.Pos")][1]','nvarchar(max)') AS AppCode
,@X.value('/ROOT[1]/RECORD[1]/SomeMore[sql:column("ai.Pos")][1]','nvarchar(max)') AS SomeMore
FROM allIDs ai
ORDER BY ai.Pos;
想法:
sql:column()
使用ID的位置读取相应的元素这应该更快:
WITH AllNodes AS
(
SELECT (ROW_NUMBER() OVER(ORDER BY (SELECT NULL))-1) / 3 AS RowGroup
,nd.value('local-name(.)','nvarchar(max)') AS NodeName
,nd.value('text()[1]','nvarchar(max)') AS NodeValue
FROM @X.nodes('/ROOT/RECORD/*') A(nd)
)
SELECT RowGroup
,MAX(CASE WHEN NodeName='ID' THEN NodeValue END) AS ID
,MAX(CASE WHEN NodeName='AppCode' THEN NodeValue END) AS AppCode
,MAX(CASE WHEN NodeName='SomeMore' THEN NodeValue END) AS SomeMore
FROm AllNodes
GROUP BY RowGroup
想法
(ROW_NUMBER-1)/3
(整数除法!)将返回一个我们可以在GROUP BY
中使用的组索引。其余的是老式的PIVOT 。两种方法的警告:
ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
的解决方案在我使用过的所有情况下都对我有用。但是值得一提的是,不能保证返回正确的位置。