简体   繁体   English

SQL / XPATH - 如何将具有相同名称的所有可能元素选择到单独的行/列中

[英]SQL / XPATH - How to select all possible elements that have the same name into separate rows/columns

I need to select all the elements under a specific node, all the elements have the same name.我需要选择特定节点下的所有元素,所有元素都具有相同的名称。

Tables


Lets say I have 2 tables in my database; 假设我的数据库中有 2 个表;
  1. [Access_Groups], This table contains all the groups that can access my application [Access_Groups],此表包含可以访问我的应用程序的所有组

  2. [User_Accounts], This table contains user details and an XML file that contains their access groups [User_Accounts],此表包含用户详细信息和包含其访问组的 XML 文件

I want to see which users have access groups in their XML file, that match the groups in my [Access_Groups] table我想查看哪些用户在他们的 XML 文件中有访问组,与我的 [Access_Groups] 表中的组匹配

XML File XML 文件


The XML files in [User_Accounts] look like this: [User_Accounts] 中的 XML 文件如下所示:
 <Profile> <Name>John Smith</Name> <Role>Developer</Role> </Profile> <Groups> <String>Group_1</String> <String>Group_2</String> <String>Group_3</String> <String>Group_4</String> <String>Group_5</String> <String>Group_6</String> </Groups>

Query询问


If i run this following query: 如果我运行以下查询:
SELECT 
[XML].value('(//Groups/*)[1]', 'varchar(max)') AS 'XMl_1',
[XML].value('(//Groups/*)[2]', 'varchar(max)') AS 'XMl_2',
[XML].value('(//Groups/*)[3]', 'varchar(max)') AS 'XMl_3',
[XML].value('(//Groups/*)[4]', 'varchar(max)') AS 'XMl_4',
[XML].value('(//Groups/*)[5]', 'varchar(max)') AS 'XMl_5',
[XML].value('(//Groups/*)[6]', 'varchar(max)') AS 'XMl_6'
FROM [User_Accounts]

I will get the following result:我会得到以下结果:

XML XML
Group_1Group_2Group_3Group_4Group_5Group_6 Group_1Group_2Group_3Group_4Group_5Group_6

This is of no use to me as i cannot JOIN this table to [Access_Groups]这对我没有用,因为我无法将此表加入 [Access_Groups]

If I run this query instead:如果我改为运行此查询:

 SELECT [XML].value('(//Groups/*)[1]', 'varchar(max)') AS 'XMl_1', [XML].value('(//Groups/*)[2]', 'varchar(max)') AS 'XMl_2', [XML].value('(//Groups/*)[3]', 'varchar(max)') AS 'XMl_3', [XML].value('(//Groups/*)[4]', 'varchar(max)') AS 'XMl_4', [XML].value('(//Groups/*)[5]', 'varchar(max)') AS 'XMl_5', [XML].value('(//Groups/*)[6]', 'varchar(max)') AS 'XMl_6' FROM [User_Accounts]

I will get the following result:我会得到以下结果:

XML_1 XML_1 XML_2 XML_2 XML_3 XML_3 XML_4 XML_4 XML_5 XML_5 XML_6 XML_6
Group_1 Group_1 Group_2 Group_2 Group_3 Group_3 Group_4 Group_4 Group_5 Group_5 Group_6 Group_6

I could JOIN this results set to [Access_Groups], However this is no use to me as i have to define every single column. 我可以将此结果集加入 [Access_Groups],但这对我没有用,因为我必须定义每一列。 Some users may have up to 100 groups. 一些用户可能有多达 100 个组。

Solution解决方案


Is there no way i can do something like this?: 有没有办法我可以做这样的事情?:
 SELECT [Name], [XML].value('(//Groups)[*]', 'varchar(max)') AS 'XML' FROM [User_Accounts]

To get a result set like this:要获得这样的结果集:

Name姓名 XML XML
John Smith约翰·史密斯 Group_1 Group_1
John Smith约翰·史密斯 Group_2 Group_2
John Smith约翰·史密斯 Group_3 Group_3
John Smith约翰·史密斯 Group_4 Group_4
John Smith约翰·史密斯 Group_5 Group_5
John Smith约翰·史密斯 Group_6 Group_6

I could then SELECT FROM that results set WHERE IN (SELECT * FROM [ACCESS_GROUPS]) to determine if this user had access to my application然后我可以 SELECT FROM that results set WHERE IN (SELECT * FROM [ACCESS_GROUPS]) 以确定该用户是否有权访问我的应用程序

Obviously though:不过很明显:

 SELECT [Name], [XML].value('(//Groups)[*]', 'varchar(max)') AS 'XML' FROM [User_Accounts]

This does not work!这不起作用!

Has anyone got any idea of how i could compare all the 'String' nodes for each user to my [Access_Groups] table?有没有人知道我如何将每个用户的所有“字符串”节点与我的 [Access_Groups] 表进行比较?

Thanks!谢谢!

This is my first post, so it might be a bit rubbish这是我的第一篇文章,所以可能有点垃圾

This is possible, you need to use nodes() to expand your XML into rows, eg这是可能的,您需要使用nodes()将您的 XML 扩展为行,例如

DECLARE @User_Accounts TABLE ([XML] XML);
INSERT @User_Accounts ([XML]) VALUES('<Profile>
    <Name>John Smith</Name>
    <Role>Developer</Role>
</Profile>
<Groups>
    <String>Group_1</String>
    <String>Group_2</String>
    <String>Group_3</String>
    <String>Group_4</String>
    <String>Group_5</String>
    <String>Group_6</String>
</Groups>');


SELECT  Name = ua.[XML].value('(Profile/Name/text())[1]', 'VARCHAR(100)'),
        Role = ua.[XML].value('(Profile/Role/text())[1]', 'VARCHAR(100)'),
        GroupName = g.x.value('text()[1]', 'VARCHAR(100)')
FROM    @User_Accounts AS ua
CROSS APPLY ua.[XML].nodes('/Groups/String') AS g (x);

Example on db<>fiddle db<>fiddle 上的示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM