SQL 在逗号分隔行加入
SQL Join on Comma Separated Row
我正在使用 SQL Server 2014,我有一个 table(示例),如下所示:
| Hosts | Description |
|------------------------------------------------------|
| 192.168.0.1,192.168.0.2,192.168.0.3 | Group A |
| 192.168.0.10,192.168.0.13,192.168.0.15 | Group B |
| 192.168.0.22 | Group C |
|------------------------------------------------------|
我想在新的 table:
中获取这些数据
| Hosts | Description |
|-------------------------------|
| 192.168.0.1 | Group A |
| 192.168.0.2 | Group A |
| 192.168.0.3 | Group A |
| 192.168.0.10 | Group B |
| 192.168.0.13 | Group B |
| 192.168.0.15 | Group B |
| 192.168.0.22 | Group C |
|-------------------------------|
我做了什么:
-- List comma separated hosts in a new table (this part is working good)
set @abc = (select hosts from example for xml path(''))
set @xyz = (select replace(replace(@abc,'<HOSTS>',','),'</HOSTS>',''))
select * into newtable from split(@xyz, ',')
--My Join
select newtable.item, example.description
from newtable
left join example on newtable.item like '%' + example.hosts + '%'
但我得到:
| Hosts | Description |
|-------------------------------|
| 192.168.0.1 | NULL |
| 192.168.0.2 | NULL |
| 192.168.0.3 | NULL |
| 192.168.0.10 | NULL |
| 192.168.0.13 | NULL |
| 192.168.0.15 | NULL |
| 192.168.0.22 | Group C |
|-------------------------------|
基本上,只有当我的主机值单独位于该行时,我的连接才有效。我希望通过我的查询“'%' + example.hosts + '%'”解决这个问题,但没有。
我尝试使用相同的逻辑使用“交叉应用”和“连接”但没有成功。
如您所见,我在 SQL 方面的知识不多,我觉得我缺少一些基本的东西,尽管我已经坚持了很长时间。
我指望你的帮助,谢谢!
也许你应该做如下的事情:
SELECT Description,Split.a.value('.', 'VARCHAR(max)') 'Hosts'
FROM
(
SELECT Description, CAST ('<X>' + REPLACE(Hosts, ',', '</X><X>') + '</X>' AS XML) AS Data
FROM example
) AS A
CROSS APPLY Data.nodes ('/X') AS Split(a)
请尝试以下解决方案。
它正在使用 XML 和 XQuery。
要点:
- 没有派生表或 CTE。
- CData 部分防止 & 号等字符。
- XPath 表达式包含
text()
以获得最佳性能。 SQL 服务器特性。
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, Hosts VARCHAR(1024), Description VARCHAR(30));
INSERT INTO @tbl (Hosts, Description) VALUES
('192.168.0.1,192.168.0.2,192.168.0.3', 'Group A'),
('192.168.0.10,192.168.0.13,192.168.0.15', 'Group B'),
('192.168.0.22', 'Group C');
-- DDL and sample data population, end
DECLARE @separator CHAR(1) = ',';
SELECT ID, [Description]
,x.value('text()[1]', 'VARCHAR(20)') AS Hosts
FROM @tbl
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(Hosts, @separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c)
CROSS APPLY c.nodes ('/root/r') AS t2(x);
输出
+----+-------------+--------------+
| ID | Description | Hosts |
+----+-------------+--------------+
| 1 | Group A | 192.168.0.1 |
| 1 | Group A | 192.168.0.2 |
| 1 | Group A | 192.168.0.3 |
| 2 | Group B | 192.168.0.10 |
| 2 | Group B | 192.168.0.13 |
| 2 | Group B | 192.168.0.15 |
| 3 | Group C | 192.168.0.22 |
+----+-------------+--------------+
我正在使用 SQL Server 2014,我有一个 table(示例),如下所示:
| Hosts | Description |
|------------------------------------------------------|
| 192.168.0.1,192.168.0.2,192.168.0.3 | Group A |
| 192.168.0.10,192.168.0.13,192.168.0.15 | Group B |
| 192.168.0.22 | Group C |
|------------------------------------------------------|
我想在新的 table:
中获取这些数据| Hosts | Description |
|-------------------------------|
| 192.168.0.1 | Group A |
| 192.168.0.2 | Group A |
| 192.168.0.3 | Group A |
| 192.168.0.10 | Group B |
| 192.168.0.13 | Group B |
| 192.168.0.15 | Group B |
| 192.168.0.22 | Group C |
|-------------------------------|
我做了什么:
-- List comma separated hosts in a new table (this part is working good)
set @abc = (select hosts from example for xml path(''))
set @xyz = (select replace(replace(@abc,'<HOSTS>',','),'</HOSTS>',''))
select * into newtable from split(@xyz, ',')
--My Join
select newtable.item, example.description
from newtable
left join example on newtable.item like '%' + example.hosts + '%'
但我得到:
| Hosts | Description |
|-------------------------------|
| 192.168.0.1 | NULL |
| 192.168.0.2 | NULL |
| 192.168.0.3 | NULL |
| 192.168.0.10 | NULL |
| 192.168.0.13 | NULL |
| 192.168.0.15 | NULL |
| 192.168.0.22 | Group C |
|-------------------------------|
基本上,只有当我的主机值单独位于该行时,我的连接才有效。我希望通过我的查询“'%' + example.hosts + '%'”解决这个问题,但没有。 我尝试使用相同的逻辑使用“交叉应用”和“连接”但没有成功。
如您所见,我在 SQL 方面的知识不多,我觉得我缺少一些基本的东西,尽管我已经坚持了很长时间。
我指望你的帮助,谢谢!
也许你应该做如下的事情:
SELECT Description,Split.a.value('.', 'VARCHAR(max)') 'Hosts'
FROM
(
SELECT Description, CAST ('<X>' + REPLACE(Hosts, ',', '</X><X>') + '</X>' AS XML) AS Data
FROM example
) AS A
CROSS APPLY Data.nodes ('/X') AS Split(a)
请尝试以下解决方案。
它正在使用 XML 和 XQuery。
要点:
- 没有派生表或 CTE。
- CData 部分防止 & 号等字符。
- XPath 表达式包含
text()
以获得最佳性能。 SQL 服务器特性。
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, Hosts VARCHAR(1024), Description VARCHAR(30));
INSERT INTO @tbl (Hosts, Description) VALUES
('192.168.0.1,192.168.0.2,192.168.0.3', 'Group A'),
('192.168.0.10,192.168.0.13,192.168.0.15', 'Group B'),
('192.168.0.22', 'Group C');
-- DDL and sample data population, end
DECLARE @separator CHAR(1) = ',';
SELECT ID, [Description]
,x.value('text()[1]', 'VARCHAR(20)') AS Hosts
FROM @tbl
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(Hosts, @separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c)
CROSS APPLY c.nodes ('/root/r') AS t2(x);
输出
+----+-------------+--------------+
| ID | Description | Hosts |
+----+-------------+--------------+
| 1 | Group A | 192.168.0.1 |
| 1 | Group A | 192.168.0.2 |
| 1 | Group A | 192.168.0.3 |
| 2 | Group B | 192.168.0.10 |
| 2 | Group B | 192.168.0.13 |
| 2 | Group B | 192.168.0.15 |
| 3 | Group C | 192.168.0.22 |
+----+-------------+--------------+