我有一个表,其中有两列 - col1 和 col2。需要汇总该表,以便如果某个值位于 col1 中,则与 col2 相邻的值将插入到原始 col1 值旁边。为了说明这一点,如果我有一个像这样的表:
col1 col2
24 670
25 980
26 24
28 1570
28 26
27 5745
27 4654
那么输出应该如下所示(没有特定的顺序):
col1 col_1 col_2 col_3 col_4
24 670 26 28 1570
25 980 NULL NULL NULL
27 4654 5745 NULL NULL
这里 col2 中的 24 已经存在于 col1 中,因此 26(以及其他关联 28 和 1570)被插入到 24 旁边。不幸的是,以我目前在 sql 方面的知识,我能够得到这个:
--refrences
-- https://stackoverflow.com/questions/38233002/how-to-create-add-columns-using-a-variable-in-a-loop
-- https://stackoverflow.com/questions/10404348/sql-server-dynamic-pivot-query
declare @max_columns int
declare @counter int
declare @col_header nvarchar(max)= ''
declare @query nvarchar(max)= ''
drop table if exists #tmp_ini
drop table if exists #tmp
drop table if exists #tmp_allcols
create table #tmp_ini (col1 int, col2 int )
create table #tmp_allcols (col1 int, col nvarchar(max), [val] int, [row_id] int)
insert into #tmp_ini values (24, 670),
(25, 980),
(26, 24),
(28, 1570),
(28, 26),
(27, 5745),
(27, 4654)
select * into #tmp from #tmp_ini
insert into #tmp_allcols
select col1,
'col_' + cast(t.row_id as nvarchar(max)) as col ,
col2 as val,
t.row_id
from (SELECT * , ROW_NUMBER() OVER ( PARTITION by col1 Order by col2 ) AS row_id FROM #tmp ) t
select @max_columns= max(m.tot) from(
select COUNT(*) as tot from #tmp_allcols group by col1
) m
set @counter=1
while @counter <= @max_columns
begin
set @col_header += 'col_' + cast(@counter as nvarchar(50)) + ', '
set @counter = @counter + 1
end
set @col_header = SUBSTRING(@col_header,1,LEN(@col_header)-1)
set @query += ' select * from ('
set @query += ' select col1, col, val from #tmp_allcols '
set @query += ' ) tmp'
set @query += ' PIVOT ( max(val) for Col in ('
set @query += @col_header
set @query += ' )) AS pvt'
print @query
exec sp_executesql @query
当前输出:
col1 col_1 col_2
24 670 NULL
25 980 NULL
26 24 NULL
27 4654 5745
28 26 1570
如有任何提示或帮助,我们将不胜感激。我看过这些帖子,但没有走得太远SQL Pivot IF EXISTS ; `PIVOT` with `EXISTS` ; `PIVOT` with `EXISTS`
最佳答案
我认为没有一种简单的方法可以满足您的需要,这就是为什么我跳过了简单的方法,并做了一些疯狂的 SQL 逻辑:
--#####################
--#### SCHEMA #########
--#####################
CREATE TABLE Entities(
entity1 int NULL,
entity2 int NULL
)
INSERT INTO Entities VALUES
(24, 670),
(25, 980),
(26, 24),
(28, 1570),
(28, 26),
(27, 5745),
(27, 4654)
--###############################
--########### QUERY #############
--###############################
IF OBJECT_ID('tempdb..#TempRelations') IS NOT NULL
DROP TABLE #TempRelations
IF OBJECT_ID('tempdb..#TempEntities') IS NOT NULL
DROP TABLE #TempEntities
IF OBJECT_ID('tempdb..#FinalRelations') IS NOT NULL
DROP TABLE #FinalRelations
IF OBJECT_ID('tempdb..#FinalTable') IS NOT NULL
DROP TABLE #FinalTable
CREATE TABLE #TempRelations (entity INT NULL)
CREATE TABLE #FinalRelations (id INT, entity INT NULL)
SELECT ROW_NUMBER() OVER (ORDER BY entity1) Id, *
INTO #TempEntities
FROM Entities
DECLARE @entity1 INT, @entity2 INT
DECLARE @count INT = (SELECT COUNT(*) FROM #TempEntities)
DECLARE @relationsCount INT = 1;
DECLARE @i INT = 1
--WHILE THERE ARE STILL ENTITIES
WHILE EXISTS(SELECT 1
FROM #TempEntities
WHERE entity1 IS NOT NULL
OR entity2 IS NOT NULL)
BEGIN
SELECT @entity1 = entity1, @entity2 = entity2
FROM #TempEntities
WHERE Id = @i
DELETE #TempRelations
IF @entity1 IS NOT NULL
BEGIN
INSERT INTO #TempRelations VALUES (@entity1)
INSERT INTO #TempRelations VALUES (@entity2)
END
UPDATE #TempEntities
SET entity1 = NULL,
entity2 = NULL
WHERE Id = @i
--WHILE THERE ARE STILL RELATIONS TO BE TAKEN FROM ENTITIES
WHILE 1=1
BEGIN
SET @i = 1
WHILE @i <= @count
BEGIN
SELECT @entity1 = entity1, @entity2 = entity2
FROM #TempEntities
WHERE Id = @i
--IF entity1 OR entity2 HAS RELATION TO THE CURRENT TEMP RELATIONS, INSERT THE RELATION THEN REMOVE THE ENTITIES
IF @entity1 IS NOT NULL AND ( EXISTS (SELECT 1
FROM #TempRelations
WHERE entity = @entity1
OR entity = @entity2) OR (SELECT COUNT(*) FROM #TempRelations) = 0 )
BEGIN
INSERT INTO #TempRelations VALUES (@entity1)
INSERT INTO #TempRelations VALUES (@entity2)
UPDATE #TempEntities
SET entity1 = NULL,
entity2 = NULL
WHERE Id = @i
END
SET @i = @i + 1
END
IF NOT EXISTS (SELECT 1
FROM #TempEntities
WHERE EXISTS (SELECT 1
FROM #TempRelations
WHERE entity = entity1
OR entity = entity2))
BREAK
END
INSERT INTO #FinalRelations
SELECT DISTINCT @relationsCount,
entity
FROM #TempRelations
SET @relationsCount = @relationsCount + 1
DELETE #TempRelations
END
SELECT 'col' + (CAST(ROW_NUMBER() OVER (PARTITION BY id ORDER BY id) AS VARCHAR)) Col,
id,
entity
INTO #FinalTable
FROM #FinalRelations
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT DISTINCT ',' + col
FROM #FinalTable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = N'SELECT ' + @cols + N' FROM
(
SELECT Col, id, entity
FROM #FinalTable
) x
PIVOT
(
MAX(entity)
FOR Col IN (' + @cols + N')
) p '
PRINT (@query)
exec sp_executesql @query;
关于sql - 通过将一列中的值引用到另一列来汇总记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73465413/