Sql 从“选择xml原始数据”获取数据

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(.

我有一个带有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(.)', '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;