使用mssql,如果我有以下数据:
cols:
id, name, list1, list2
1, 'first', '10;15;30;50', '25;12;15;18'
2, 'second', '50;30;15;10, '12;25;11;15'
...
10,'tenth', '9;2;15;1', '5;13;17;45'
im尝试创建将每个列表列连接在一起的结果行,例如
1, 'first', 10, 25
1, 'first', 15, 12
1, 'first', 30, 15
1, 'first', 50, 18
2, 'second', 50, 12
2, 'second', 30, 25
2, 'second', 15, 11
2, 'second', 10, 15
...
10, 'tenth', 9, 5
10, 'tenth', 2, 13
10, 'tenth', 15, 17
10, 'tenth', 1, 45
基本上,每个列表的每个数字都映射到该索引处的相同数字(由';'分隔)。
我可以使用cross apply
+ string_split
,但对于每种可能的组合都会产生一行(id * description * list1_size * list2_size)
在SQL中甚至有可能吗?
我还尝试使用substring
+ charindex
手动在列表中移动,但这会导致大量的手动列。
答案 0 :(得分:3)
如果列表大小相等:
SELECT 1 AS id, 'first' AS name, '10;15;30;50' AS list1, '25;12;15;18' AS list2
INTO t
UNION ALL
SELECT 2, 'second', '50;30;15;10', '12;25;11;15';
-- a bit undeterministic, ROW_NUMBER ordered by placeholder 1/0
SELECT id, name, s1.value, s2.value
FROM t
CROSS APPLY (SELECT *, ROW_NUMBER() OVER(ORDER BY 1/0) AS r FROM STRING_SPLIT(list1, ';')) s1
CROSS APPLY (SELECT *, ROW_NUMBER() OVER(ORDER BY 1/0) AS r FROM STRING_SPLIT(list2, ';')) s2
WHERE s1.r = s2.r;
相关:STRING_SPLIT Add Option to Return Row Number
使用OPENJSON
获取数组中元素的确定位置:
SELECT id, name, A.value, B.value
FROM t
CROSS APPLY (SELECT value, [key] AS rn
FROM OPENJSON(JSON_QUERY(CONCAT('[',REPLACE(t.list1,';',','),']')))) A
CROSS APPLY (SELECT value, [key] AS rn
FROM OPENJSON(JSON_QUERY(CONCAT('[',REPLACE(t.list2,';',','),']')))) B
WHERE A.rn = B.rn;
处理不同大小的列表:
WITH cte1 AS (
SELECT id, name, A.value, A.rn
FROM t
CROSS APPLY (SELECT value, [key] AS rn
FROM OPENJSON(JSON_QUERY(CONCAT('[',REPLACE(t.list1,';',','),']')))) A
),cte2 AS (
SELECT id, name, A.value, A.rn
FROM t
CROSS APPLY (SELECT value, [key] AS rn
FROM OPENJSON(JSON_QUERY(CONCAT('[',REPLACE(t.list2,';',','),']')))) A
)
SELECT id = COALESCE(cte1.id, cte2.id)
,name = COALESCE(cte1.name, cte2.name)
,cte1.value
,cte2.value
FROM cte1
FULL JOIN cte2
ON cte1.id = cte2.id
AND cte1.rn = cte2.rn
ORDER BY id;
答案 1 :(得分:2)
只要列表中的成员不超过4个,您就可以使用PARSENAME()作为快捷方式并交叉连接到仅包含数字1-4的数字表或cte。
假设您有一个名为tblNumbers
且表名为“ num”的表,类似此伪代码
SELECT id, name,
PARSENAME(REPLACE(list1, ';', '.'), tblNumbers.num) AS L1,
PARSENAME(REPLACE(list2, ';', '.'), tblNumbers.num) AS L2,
FROM YourDataTable
CROSS JOIN tblNumbers
ORDER BY id ASC, tblNumbers.num DESC
如果List
列的确包含四个以上的元素,则将无法使用PARSENAME(),但仍可以使用CROSS JOIN到Numbers表方法,并且使用UDF将不得不写那将获得列表的第N个元素。将List列和Num
值传递给该函数,就像在上面我的伪代码中将它们传递给PARSENAME一样。