![](/img/trans.png)
[英]SQL Server : splitting the results of GROUP BY into a separate columns
[英]Delimiter splitting into separate dynamic columns in SQL Server
我知道很多與此相關的問題都可以在 Google 和 SO 中找到,但具體問題不可用,所以在這里尋求偉大的人的幫助。
主要任務是在 SQL 服務器中將單個列的 pipe 分隔值拆分為多個列(值會發生變化,因此需要動態創建列)。
我瀏覽了多個鏈接並了解
2016 年后, STRING_SPLIT()
內置 function 將有助於拆分並顯示在單獨的行中(但我需要顯示在列中)。
[PIVOT]
-> PIVOT在 Static 和動態一個中都是可能的,但這對於按行順序排列的數據很有用,使其成為列順序。 但是我的表數據是按列順序排列的,Pipe 分成一列。
XML -> 這也僅限於 static(請參閱我的SQL 小提琴查詢和輸出),並且需要動態創建列而不定義查詢中的列數。
代碼:
CREATE TABLE DELIMTEDPATH
(
ID int,
Path varchar(max)
);
INSERT INTO DELIMTEDPATH
VALUES (1, 'John|Albert|James'),
(2, 'Cricket'),
(3, 'Mary|Joseph|Priyanka|Gilbert|Customer|Service|Passenger|MN-1234|MK-5678');`
;WITH SplitMenus AS
(
SELECT
ID,
CONVERT(XML, '<MENUS><Menu>' + REPLACE(Path, '|', '</Menu><Menu>') + '</Menu></MENUS>') AS Path
FROM
DELIMTEDPATH
WHERE
ID IN (1, 2, 3)
)
SELECT
ID,
Path.value('/MENUS[2]/Menu[2]', 'varchar(100)') AS Name1,
Path.value('/MENUS[2]/Menu[1]', 'varchar(100)') AS Name2,
Path.value('/MENUS[2]/Menu[3]', 'varchar(100)') AS Name3,
Path.value('/MENUS[2]/Menu[4]', 'varchar(100)') AS Name4
FROM
SplitMenus
我得到這個 output:
但是我需要的 output 是動態的,以顯示 ID=3 的所有值。
這是使用 XML、XQuery 和動態 SQL 的解決方案。
SQL
USE tempdb;
GO
-- DDL and sample data population, start
DROP TABLE IF EXISTS DELIMTEDPATH;
CREATE TABLE DELIMTEDPATH (ID INT IDENTITY PRIMARY KEY, [Path] VARCHAR(MAX));
INSERT INTO DELIMTEDPATH ([Path]) VALUES
('John|Albert|James'),
('Cricket'),
('Mary|Joseph|Priyanka|Gilbert|Customer|Service|Passenger|MN-1234|MK-5678');
-- DDL and sample data population, end
DECLARE @separator CHAR(1) = '|'
, @CrLf CHAR(2) = CHAR(13) + CHAR(10)
, @nameCounter INT
, @i INT = 1;
SET @nameCounter = (SELECT MAX(LEN([Path]) - LEN(REPLACE([Path], @separator,'')))/COALESCE(NULLIF(LEN(@separator), 0), 1) AS cnt
FROM DELIMTEDPATH) + 1;
DECLARE @SQL NVARCHAR(MAX) =
N';WITH rs AS
(
SELECT ID,
CAST(''<root><r>'' + REPLACE([Path], ''' + @separator + ''', ''</r><r>'') + ''</r></root>'' AS XML) AS xmldata
FROM DELIMTEDPATH
)
SELECT ID' + @CrLf;
WHILE @i <= @nameCounter BEGIN
SET @SQL += ', c.value(''(r[' + CAST(@i AS VARCHAR(3)) + ']/text())[1]'', ''VARCHAR(100)'') AS Name' + CAST(@i AS VARCHAR(3)) + @CrLf
SET @i += 1
END
SET @SQL += 'FROM rs CROSS APPLY xmldata.nodes(''/root'') AS t(c);'
-- just to see it
PRINT @sql;
-- we are ready at this point
EXEC sp_executesql @SQL;
Output
+----+---------+--------+----------+---------+----------+---------+-----------+---------+
| ID | Name1 | Name2 | Name3 | Name4 | Name5 | Name6 | Name7 | Name8 |
+----+---------+--------+----------+---------+----------+---------+-----------+---------+
| 1 | John | Albert | James | NULL | NULL | NULL | NULL | NULL |
| 2 | Cricket | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 3 | Mary | Joseph | Priyanka | Gilbert | Customer | Service | Passenger | MN-1234 |
+----+---------+--------+----------+---------+----------+---------+-----------+---------+
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.