Sql server 通过select语句将xml节点获取为逗号分隔的列表

Sql server 通过select语句将xml节点获取为逗号分隔的列表,sql-server,tsql,Sql Server,Tsql,Xml存储在varchar列中 其中一个节点类似于 <PreviousItem> <string>501</string> <string>502</string> <string>505</string> </PreviousItem> 以上是给我以前的项目作为50150505 我尝试了以下内容,但在CASTcSettings AS XML中,关键字“AS”附近的语法不正确 这里有一种方法: --

Xml存储在varchar列中

其中一个节点类似于

<PreviousItem>
<string>501</string>
<string>502</string>
<string>505</string>
</PreviousItem>
以上是给我以前的项目作为50150505

我尝试了以下内容,但在CASTcSettings AS XML中,关键字“AS”附近的语法不正确

这里有一种方法:

-- Sample Data
DECLARE @tblX TABLE (cID int identity, cSettings xml);
INSERT @tblX (cSettings)
VALUES 
('<PreviousItem>
<string>501</string>
<string>502</string>
<string>505</string>
</PreviousItem>'),
('<PreviousItem>
<string>4433</string>
<string>5577</string>
</PreviousItem>');

-- Solution
SELECT 
  cID,
  PreviousItem = STUFF
  (
    (
      SELECT ',' + x.value('(text())[1]', 'varchar(500)')
      FROM @tblX t
      CROSS APPLY cSettings.nodes('/PreviousItem/string') x(x)
      WHERE t.cID = tx.cId
      FOR XML PATH('')
    ),1,1,''
  )
FROM @tblX tx;
基于您的示例数据,您有一个注册类型,它存在于您的XML中,您需要获取。。。这是我的第一个解决方案的调整版本

-- Updated Sample Data with RegistrationType
DECLARE @tblX TABLE (cID int identity, cSettings xml);
INSERT @tblX (cSettings)
VALUES 
('<PreviousItem>
<string>501</string>
<string>502</string>
<string>505</string>
</PreviousItem>
<RegistrationType>Type A</RegistrationType>
'),
('<PreviousItem>
<string>4433</string>
<string>5577</string>
</PreviousItem>
<RegistrationType>Type B</RegistrationType>
');

-- Solution which includes RegistrationType
SELECT 
  cID,
  PreviousItem = STUFF
  (
    (
      SELECT ',' + x.value('(text())[1]', 'varchar(500)')
      FROM @tblX t
      CROSS APPLY cSettings.nodes('/PreviousItem/string') x(x)
      WHERE t.cID = tx.cId
      FOR XML PATH('')
    ),1,1,''
  ),    
  RegistrationType = STUFF
  (
    (
      SELECT ',' + x.value('(text())[1]', 'varchar(500)')
      FROM @tblX t
      CROSS APPLY cSettings.nodes('RegistrationType') x(x)
      WHERE t.cID = tx.cId
      FOR XML PATH('')
    ),1,1,''
  )
FROM @tblX tx;
为了获得更准确的解决方案,请包含一些DDL和可消耗样本数据,我可以相应地修改我的解决方案

更新:因为您的XML数据存储为文本,所以您需要调整我的原始解决方案,如下所示:

-- Updated Sample Data with RegistrationType
DECLARE @tblX TABLE (cID int identity, cSettings varchar(max));
INSERT @tblX (cSettings)
VALUES 
('<PreviousItem>
<string>501</string>
<string>502</string>
<string>505</string>
</PreviousItem>
<RegistrationType>Type A</RegistrationType>
'),
('<PreviousItem>
<string>4433</string>
<string>5577</string>
</PreviousItem>
<RegistrationType>Type B</RegistrationType>
');

-- Solution which includes RegistrationType
SELECT 
  cID,
  PreviousItem = STUFF
  (
    (
      SELECT ',' + x.value('(text())[1]', 'varchar(500)')
      FROM @tblX t
      CROSS APPLY (VALUES (CAST(cSettings AS xml))) xx(xx)
      CROSS APPLY xx.xx.nodes('/PreviousItem/string') x(x)
      WHERE t.cID = tx.cId
      FOR XML PATH('')
    ),1,1,''
  ),
  RegistrationType = STUFF
  (
    (
      SELECT ',' + x.value('(text())[1]', 'varchar(500)')
      FROM @tblX t
      CROSS APPLY (VALUES (CAST(cSettings AS xml))) xx(xx)
      CROSS APPLY xx.xx.nodes('RegistrationType') x(x)
      WHERE t.cID = tx.cId
      FOR XML PATH('')
    ),1,1,''
  )
FROM @tblX tx;

因为您处理的是文本而不是XML,所以可以使用一些基本的T-SQL之类的工具来更有效地处理这个问题:


XML存储在varchar中有什么原因吗?作为一般规则,建议您使用该工作的权限。这有几个好处,包括:更难输入无效数据,更容易处理。例如,不需要每次强制转换列。可能的重复我对数据库没有任何控制权,我是这样得到的,所以不知道为什么。感谢回复!我的xml驻留在varchar字段中,而不是xml。您的示例使用的是.node,它只适用于xml类型。我更新了答案,以处理存储为varchar的数据。谢谢,这正是我所需要的!
-- Updated Sample Data with RegistrationType
DECLARE @tblX TABLE (cID int identity, cSettings xml);
INSERT @tblX (cSettings)
VALUES 
('<PreviousItem>
<string>501</string>
<string>502</string>
<string>505</string>
</PreviousItem>
<RegistrationType>Type A</RegistrationType>
'),
('<PreviousItem>
<string>4433</string>
<string>5577</string>
</PreviousItem>
<RegistrationType>Type B</RegistrationType>
');

-- Solution which includes RegistrationType
SELECT 
  cID,
  PreviousItem = STUFF
  (
    (
      SELECT ',' + x.value('(text())[1]', 'varchar(500)')
      FROM @tblX t
      CROSS APPLY cSettings.nodes('/PreviousItem/string') x(x)
      WHERE t.cID = tx.cId
      FOR XML PATH('')
    ),1,1,''
  ),    
  RegistrationType = STUFF
  (
    (
      SELECT ',' + x.value('(text())[1]', 'varchar(500)')
      FROM @tblX t
      CROSS APPLY cSettings.nodes('RegistrationType') x(x)
      WHERE t.cID = tx.cId
      FOR XML PATH('')
    ),1,1,''
  )
FROM @tblX tx;
-- Updated Sample Data with RegistrationType
DECLARE @tblX TABLE (cID int identity, cSettings varchar(max));
INSERT @tblX (cSettings)
VALUES 
('<PreviousItem>
<string>501</string>
<string>502</string>
<string>505</string>
</PreviousItem>
<RegistrationType>Type A</RegistrationType>
'),
('<PreviousItem>
<string>4433</string>
<string>5577</string>
</PreviousItem>
<RegistrationType>Type B</RegistrationType>
');

-- Solution which includes RegistrationType
SELECT 
  cID,
  PreviousItem = STUFF
  (
    (
      SELECT ',' + x.value('(text())[1]', 'varchar(500)')
      FROM @tblX t
      CROSS APPLY (VALUES (CAST(cSettings AS xml))) xx(xx)
      CROSS APPLY xx.xx.nodes('/PreviousItem/string') x(x)
      WHERE t.cID = tx.cId
      FOR XML PATH('')
    ),1,1,''
  ),
  RegistrationType = STUFF
  (
    (
      SELECT ',' + x.value('(text())[1]', 'varchar(500)')
      FROM @tblX t
      CROSS APPLY (VALUES (CAST(cSettings AS xml))) xx(xx)
      CROSS APPLY xx.xx.nodes('RegistrationType') x(x)
      WHERE t.cID = tx.cId
      FOR XML PATH('')
    ),1,1,''
  )
FROM @tblX tx;
-- Updated Sample Data with RegistrationType
DECLARE @tblX TABLE (cID int identity, cSettings varchar(max));
INSERT @tblX (cSettings)
VALUES 
('<PreviousItem>
<string>501</string>
<string>502</string>
<string>505</string>
</PreviousItem>
<RegistrationType>Type A</RegistrationType>
'),
('<PreviousItem>
<string>4433</string>
<string>5577</string>
</PreviousItem>
<RegistrationType>Type B</RegistrationType>
');

-- Solution using PatExclude8K
SELECT
  cID, 
  PreviousItem     = SUBSTRING(NewString,1, LEN(NewString)-1),
  RegistrationType = SUBSTRING
  (
    cSettings,
    CHARINDEX('<RegistrationType>', cSettings)+18,
    CHARINDEX('</RegistrationType>', cSettings) - 
      (CHARINDEX('<RegistrationType>', cSettings)+18)
  )
FROM @tblX o
CROSS APPLY dbo.PatExclude8K(REPLACE(cSettings,'</string>',','), '[^0-9,]');