我尝试使用像Pivot这样的东西寻找问题的解决方案,但它们似乎没有给出我正在查看的输出,因为它们似乎将一行中的特定值映射到列。
我有两列,第一列包含"键"字段和第二个正在改变数据。 e.g。
╔══════════╦══════════════════╗
║ Project ║ Location ║
╠══════════╬══════════════════╣
║ ProjectA ║ \\Server1\Share1 ║
║ ProjectA ║ \\Server2\Share1 ║
║ ProjectB ║ \\Server6\Share2 ║
║ ProjectB ║ \\Server1\Share2 ║
║ ProjectB ║ \\Server2\Share3 ║
║ ProjectC ║ \\Server8\Share2 ║
║ ProjectD ║ \\Server5\Share9 ║
║ ProjectD ║ \\ServerX\ShareY ║
╚══════════╩══════════════════╝
我想要实现的输出如下:
╔══════════╦══════════════════╦══════════════════╦══════════════════╦═════════╦══════════╦═════════╗
║ Project ║ Column1 ║ Column2 ║ Column3 ║ Column4 ║ Column5 ║ ColumnX ║
╠══════════╬══════════════════╬══════════════════╬══════════════════╬═════════╬══════════╬═════════╣
║ ProjectA ║ \\Server1\Share1 ║ \\Server2\Share1 ║ NULL ║ NULL ║ NULL ║ ║
║ ProjectB ║ \\Server1\Share2 ║ \\Server2\Share3 ║ \\Server6\Share2 ║ NULL ║ NULL ║ ║
║ ProjectC ║ \\Server8\Share2 ║ NULL ║ NULL ║ NULL ║ NULL ║ ║
║ ProjectD ║ \\Server5\Share9 ║ \\ServerX\ShareY ║ NULL ║ NULL ║ NULL ║ ║
╚══════════╩══════════════════╩══════════════════╩══════════════════╩═════════╩══════════╩═════════╝
如果该列没有数据,那么它将为NULL。
位置列中的不同值的数量是动态的,所需的输出是通用列名称,在相应的项目值旁边具有不同的位置值。
希望有人可以帮助我解决这个问题,因为它让我发疯了!
提前致谢。
忍
答案 0 :(得分:1)
警告:强>
此解决方案假设它将是最多6列,您可以添加更多,例如最多20列。
<强> LiveDemo 强>
数据:
CREATE TABLE #mytable(
Project VARCHAR(80) NOT NULL
,Location VARCHAR(160) NOT NULL
);
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server1\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server2\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server6\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server1\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server2\Share3');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectC','\\Server8\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\Server5\Share9');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\ServerX\ShareY');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\ServerX\ShareY');
查询:
WITH cte AS
(
SELECT Project, Location,
[rn] = RANK() OVER (PARTITION BY Project ORDER BY Location)
FROM #mytable
)
SELECT
Project
,Column1 = MAX(CASE WHEN rn = 1 THEN Location ELSE NULL END)
,Column2 = MAX(CASE WHEN rn = 2 THEN Location ELSE NULL END)
,Column3 = MAX(CASE WHEN rn = 3 THEN Location ELSE NULL END)
,Column4 = MAX(CASE WHEN rn = 4 THEN Location ELSE NULL END)
,Column5 = MAX(CASE WHEN rn = 5 THEN Location ELSE NULL END)
,Column6 = MAX(CASE WHEN rn = 6 THEN Location ELSE NULL END)
-- ....
-- ,ColumnX = MAX(CASE WHEN rn = X THEN Location ELSE NULL END)
FROM cte
GROUP BY Project;
使用Dynamic-SQL并生成Pivoted列列表的真正通用解决方案:
<强> LiveDemo2 强>
DECLARE @cols NVARCHAR(MAX),
@cols_piv NVARCHAR(MAX),
@query NVARCHAR(MAX)
,@max INT = 0;
SELECT @max = MAX(c)
FROM (
SELECT Project, COUNT(DISTINCT Location) AS c
FROM #mytable
GROUP BY Project) AS s;
SET @cols = STUFF(
(SELECT ',' + CONCAT('[',c.n, '] AS Column',c.n, ' ')
FROM ( SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n)
WHERE c.n <= @max
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SET @cols_piv = STUFF(
(SELECT ',' + CONCAT('[',c.n, '] ')
FROM ( SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n)
WHERE c.n <= @max
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
-- SELECT @cols;
set @query = N'SELECT Project, ' + @cols + ' from
(
select Project, Location,
[rn] = RANK() OVER (PARTITION BY Project ORDER BY Location)
from #mytable
) x
pivot
(
max(Location)
for rn in (' + @cols_piv + ')
) p ';
-- SELECT @query;
EXEC [dbo].[sp_executesql]
@query;
答案 1 :(得分:0)
归功于@ lad2025。
我正在使用Server2005,所以这些是我为了让它适合我而必须做的修改:
@max INT = 0;
CONCAT
函数不存在,因此在参数之间用+替换。 ', ' + '[' + convert(varchar, c.n) + '] AS Column' + c.n
CONVERT
将其VARCHAR
- CONVERT(VARCHAR, c.n)
GROUP BY
,否则数据会显示在奇怪的列号中。 没有GROUP BY
如果没有GROUP BY
,因为初始#mytable
中的数据越多,结果就会显示在非连续的列中。
╔══════════╦══════════════════╦══════════════════╦══════════════════╦══════╦══════════════════╦══════╗
║ Project ║ Col1 ║ Col2 ║ Col3 ║ Col4 ║ Col5 ║ Col6 ║
╠══════════╬══════════════════╬══════════════════╬══════════════════╬══════╬══════════════════╬══════╣
║ ProjectA ║ \\Server1\Share1 ║ \\Server2\Share1 ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectB ║ \\Server1\Share2 ║ \\Server2\Share3 ║ \\Server6\Share2 ║ NULL ║ NULL ║ NULL ║
║ ProjectC ║ \\Server8\Share2 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectD ║ NULL ║ \\Server5\Share9 ║ NULL ║ NULL ║ \\ServerX\ShareY ║ NULL ║
╚══════════╩══════════════════╩══════════════════╩══════════════════╩══════╩══════════════════╩══════╝
使用GROUP BY
应该如此。
╔══════════╦══════════════════╦══════════════════╦══════════════════╦══════╦══════╦══════╗
║ Project ║ Col1 ║ Col2 ║ Col3 ║ Col4 ║ Col5 ║ Col6 ║
╠══════════╬══════════════════╬══════════════════╬══════════════════╬══════╬══════╬══════╣
║ ProjectA ║ \\Server1\Share1 ║ \\Server2\Share1 ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectB ║ \\Server1\Share2 ║ \\Server2\Share3 ║ \\Server6\Share2 ║ NULL ║ NULL ║ NULL ║
║ ProjectC ║ \\Server8\Share2 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectD ║ \\Server5\Share9 ║ \\ServerX\ShareY ║ NULL ║ NULL ║ NULL ║ NULL ║
╚══════════╩══════════════════╩══════════════════╩══════════════════╩══════╩══════╩══════╝
数据:强>
CREATE TABLE #mytable(
Project VARCHAR(80) NOT NULL
,Location VARCHAR(160) NOT NULL
);
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server1\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server2\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server6\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server1\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server2\Share3');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectC','\\Server8\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\Server5\Share9');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\ServerX\ShareY');
<强>查询:强>
DECLARE @cols NVARCHAR(MAX),
@cols_piv NVARCHAR(MAX),
@query NVARCHAR(MAX)
,@max INT;
SELECT @max = MAX(c)
FROM (
SELECT Project, COUNT(DISTINCT Location) AS c
FROM #mytable
GROUP BY Project) AS s;
SET @cols = STUFF(
(SELECT ', ' + '[' + convert(varchar, c.n) + '] AS Column' + convert(varchar, c.n)
FROM ( SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n)
WHERE c.n <= @max
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SET @cols_piv = STUFF(
(SELECT ',' + '[' + convert(varchar, c.n) + ']'
FROM ( SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n)
WHERE c.n <= @max
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
,1,1,'');
set @query = N'SELECT Project, ' + @cols + ' from
(
select Project, Location,
[rn] = RANK() OVER (PARTITION BY Project ORDER BY Location)
from #mytable
GROUP BY Project, Location
) x
pivot
(
max(Location)
for rn in (' + @cols_piv + ')
) p ';
EXEC [dbo].[sp_executesql]
@query;