我有一张桌子
Values
Values
表:
艺术ID | 变量ID | 顺序 | Val1 | Val2 | Val3 | Val4 | Val5 | Val6 | Val7 | Val8 | 瓦尔9 | Val10 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | A1-Val3 | |||||||||
2 | 1 | 2 | A2-Val6 | |||||||||
3 | 2 | 3 | A3-Val1 | |||||||||
4 | 2 | 4 | A4-Val4 | A4-Val9 | ||||||||
5 | 3 | 5 | A5-Val2 | A5-Val5 |
值根据 VarId 向上移动。对于 VarId = 1,有 2 行。 Val3 列中的条目转移到 Val1,这对于 VarId = 1 的所有记录都是相同的。因此,下一个值(即 Val6 列中的 A2-Val6)将转移到 VarId = 1 的下一个空闲列。在这种情况下,它是Val2 列。
表格的最终预期结果是
预期
Values
表:
艺术ID | 变量ID | 顺序 | Val1 | Val2 | Val3 | Val4 | Val5 | Val6 | Val7 | Val8 | 瓦尔9 | Val10 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | A1-Val3 | |||||||||
2 | 1 | 2 | A2-Val6 | |||||||||
3 | 2 | 3 | A3-Val1 | |||||||||
4 | 2 | 4 | A4-Val4 | A4-Val9 | ||||||||
5 | 3 | 5 | A5-Val2 | A5-Val5 |
上表为示例。实际的表包含超过 100 万条记录,列数最多可达 100。(我知道,表中有那么多列不好,但无法更改)。
我实施了该解决方案,它返回了预期的结果。但是,我想提高数据量大时的性能。
DECLARE @start INT = 1, @end INT = 10
DECLARE @valueTable NVARCHAR(100) = N'[Values]'
DECLARE @valueColumns NVARCHAR(MAX) = N''
DECLARE @numColumns NVARCHAR(MAX)= N''
DECLARE @numColumnsWithoutNull NVARCHAR(MAX) = N''
DECLARE @attNumber NVARCHAR(3)
DECLARE @separator VARCHAR(1) = ','
WHILE @start <= @end
BEGIN
SET @attNumber = CAST(@start AS NVARCHAR(3))
IF @start = @end
BEGIN
SET @separator = N''
END
SET @valueColumns += N'Val'+ @attNumber +''+@separator+''
SET @numColumns += N'['+ @attNumber +']'+@separator+''
SET @numColumnsWithoutNull += N'ISNULL(['+ @attNumber +'],'''') AS ['+ @attNumber +']'+@separator+''
SET @start = @start +1
END
DECLARE @result NVARCHAR(MAX) =N'
DROP TABLE IF EXISTS #TempCache;
SELECT * INTO #TempCache
FROM
(
SELECT ArtId, VarId, Sequence, '+@numColumnsWithoutNull+'
FROM
(
SELECT VarId, ArtId, Sequence, Value, DENSE_RANK() OVER (PARTITION BY VariationGroupId ORDER BY [Cols]) AS RowId
FROM
(SELECT * FROM '+@valueTable+' ) AS T1
UNPIVOT
(value FOR [Cols] IN ('+@valueColumns+')) AS unpvt
WHERE Value <> ''''
) T
PIVOT
(
MAX([value]) FOR RowId IN ('+@numColumns+')
) AS pvt
) Temp;
TRUNCATE TABLE '+@valueTable+';
INSERT INTO '+@valueTable+'
SELECT * FROM #TempCache
ORDER BY Sequence
'
--SET STATISTICS XML ON;
exec sp_executesql @result
--SET STATISTICS XML OFF;
您可以利用像 json_array() 这样的函数来去除空值,算法如下: 在子查询的最内层:
select ArtId, VarId, Sequence,json_array(Val1, Val2, Val3, Val4, Val5, Val6, Val7, Val8, Val9, Val10) as js
from values
结果应该是:
1 1 1 ["A1-Val3"]
2 1 2 [" ","A2-Val6"]
3 2 3 ["A3-Val1"]
4 2 4 [" ","A4-Val4","A4-Val9"]
5 3 5 ["A5-Val2","A5-Val5"]
然后您可以使用该查询作为 MERGE 语句中的源,使用 JSON_VALUE(result_array, '$[N]') 更新原始列,其中 N 从 0 到 N cols-1。
这样你就有了一个纯 SQL 解决方案。