Sql 从“选择xml原始数据”获取数据
我有一个带有select for xml raw语句的查询。结果看起来像Sql 从“选择xml原始数据”获取数据,sql,sql-server,xml,Sql,Sql Server,Xml,我有一个带有select for xml raw语句的查询。结果看起来像 <row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="1" /> <row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="2" /> 但是节点属性是动态的 我可以使用获取id和值的列表 select t.c.value('local-name(.
<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="1" />
<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="2" />
但是节点属性是动态的
我可以使用获取id和值的列表
select
t.c.value('local-name(.)', 'nvarchar(128)') as [id],
t.c.value('.', 'nvarchar(128)') as [value]
from @XMLVal.nodes('row/@*') as t(c)
使现代化
我的解决方案
declare
@colNames TABLE(
id INT IDENTITY,
colName nvarchar(max)
);
declare @XMLVal XML;
set @XMLVal = '<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="1" />
<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="2" />';
-----DEFINE COLUMN NAMES-------------
insert into @colNames
select distinct
t.c.value('local-name(.)', 'nvarchar(128)') as [ID]
from @XMLVal.nodes('row/@*') as t(c)
-----COUNT COLUMNS QNTY---------------------
DECLARE @MaxCount INT;
SELECT @MaxCount = count(*) from @colNames
-----GENERATE SQL---------------------------
DECLARE @SQL NVARCHAR(max), @i INT, @curentColumnName nvarchar(max);
SET @i = 0;
SET @SQL = 'declare @XMLVal XML;
SET @XMLVal = ''<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="1" />
<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="2" />'';
select ';
WHILE @i < @MaxCount
BEGIN
SET @i = @i + 1;
select @curentColumnName = colName from @colNames where id = @i;
SET @SQL = @SQL + ' t.c.value(''@' + @curentColumnName + ''', ''nvarchar(128)'') as ' + @curentColumnName;
if (@i < @MaxCount ) begin
SET @SQL = @SQL + ', ';
end
END
SET @SQL = @SQL + ' from @XMLVal.nodes(''/row'') as t(c)';
EXEC sp_executesql @SQL;
在您详细了解目标的情况下,使用XPath直接处理XML的元素和属性要容易得多 对于未知XML的一般读取,您的方法是完全可以的,但这里要复杂得多。您必须首先按行读取属性,然后使用MaxCASE执行某种透视或分组。。。把它们当作普通桌子拿回来 请注意,您的XML似乎没有根元素。这在SQL查询中是可能的,但是-严格地说-无效
DECLARE @XMLVal XML=
'<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="1" />
<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="2" />';
select
t.c.value('@link', 'nvarchar(128)') as link,
t.c.value('@DATASOURCE', 'nvarchar(128)') as DATASOURCE,
t.c.value('@obj_id', 'int') as obj_id,
t.c.value('@err_id', 'int') as err_id
from @XMLVal.nodes('/row') as t(c)
主要问题是属性是动态的,名称和数量以前不知道execution@AlexanderZInchenko,这是一个完全不同的问题,你应该在你的问题中提到。。。请提供一些不同结构的XML片段。并请提供详细的名称和数量是未知的:完全免费?是否有一组确定的属性?至少每一组行是相同的还是在一组行中有所不同?例如,目标表包含两个单元格。1:“”2:“”名称和数量完全免费。我不需要同时查询不同的单元格。您就是向导!多谢各位@AlexanderZInchenko不是因为某些原因。。。必须将变量@RowID设置为所需的行。您可能会删除此筛选器,但随后会以某种方式混合所有属性的所有行:
declare
@colNames TABLE(
id INT IDENTITY,
colName nvarchar(max)
);
declare @XMLVal XML;
set @XMLVal = '<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="1" />
<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="2" />';
-----DEFINE COLUMN NAMES-------------
insert into @colNames
select distinct
t.c.value('local-name(.)', 'nvarchar(128)') as [ID]
from @XMLVal.nodes('row/@*') as t(c)
-----COUNT COLUMNS QNTY---------------------
DECLARE @MaxCount INT;
SELECT @MaxCount = count(*) from @colNames
-----GENERATE SQL---------------------------
DECLARE @SQL NVARCHAR(max), @i INT, @curentColumnName nvarchar(max);
SET @i = 0;
SET @SQL = 'declare @XMLVal XML;
SET @XMLVal = ''<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="1" />
<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="2" />'';
select ';
WHILE @i < @MaxCount
BEGIN
SET @i = @i + 1;
select @curentColumnName = colName from @colNames where id = @i;
SET @SQL = @SQL + ' t.c.value(''@' + @curentColumnName + ''', ''nvarchar(128)'') as ' + @curentColumnName;
if (@i < @MaxCount ) begin
SET @SQL = @SQL + ', ';
end
END
SET @SQL = @SQL + ' from @XMLVal.nodes(''/row'') as t(c)';
EXEC sp_executesql @SQL;
DECLARE @XMLVal XML=
'<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="1" />
<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="2" />';
select
t.c.value('@link', 'nvarchar(128)') as link,
t.c.value('@DATASOURCE', 'nvarchar(128)') as DATASOURCE,
t.c.value('@obj_id', 'int') as obj_id,
t.c.value('@err_id', 'int') as err_id
from @XMLVal.nodes('/row') as t(c)
CREATE TABLE #tbl(ID INT IDENTITY,XMLVal XML);
INSERT INTO #tbl VALUES
('<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="1" />
<row link="someLink" DATASOURCE="SomeSystem" obj_id="1" err_id="2" />')
,('<row UWI="123" Xcord="2.4" obj_id="1" err_id="1" />
<row lUWI="122" Xcord="1.4" obj_id="1" err_id="2" />');
DECLARE @RowID INT=2;
DECLARE @columnNames AS NVARCHAR(MAX)=
STUFF(
(
SELECT DISTINCT ',' + t.c.value('local-name(.)', 'nvarchar(128)')
FROM #tbl AS tbl
CROSS APPLY XMLVal.nodes('row/@*') as t(c)
WHERE ID=@RowID
FOR XML PATH('')
),1,1,''
);
DECLARE @cmd NVARCHAR(MAX)=
N'SELECT p.*
FROM
(
SELECT
t.c.value(''local-name(.)'', ''nvarchar(128)'') as [colname],
t.c.value(''.'', ''nvarchar(128)'') as [value]
FROM #tbl AS tbl
CROSS APPLY XMLVal.nodes(''row/@*'') as t(c)
WHERE ID=' + CAST(@RowID AS NVARCHAR(10)) +
') AS tbl
PIVOT
(
MAX(value) FOR colname IN(' + @columnNames + ')
) AS p';
EXEC(@cmd);
GO
DROP TABLE #tbl;