我正在尝试创建一个数据透视表。消息来源如下:
+--------+------------+-----------+--------+--------+------------+
| UserId | LastName | FirstName | Param1 | Param2 | Date |
+--------+------------+-----------+--------+--------+------------+
| 1 | Snow | John | Text1 | Text1 | 01-01-2019 |
| 2 | Lannister | Tyrion | Text1 | Text1 | 01-01-2019 |
| 3 | Targaryen | Daenerys | Text2 | Text2 | 01-01-2019 |
| 1 | Snow | John | Text3 | Text2 | 01-02-2019 |
| 2 | Lannister | Tyrion | Text3 | Text2 | 01-02-2019 |
| 3 | Targaryen | Daenerys | Text3 | Text3 | 01-02-2019 |
| | | | | | … 120 days |
+--------+------------+-----------+--------+--------+------------+
这就是我想要实现的目标:
+--------+------------+-----------+-------------------+-------------------+-------------------+-------------------+---+
| UserId | LastName | FirstName | Param1:01-01-2019 | Param2:01-01-2019 | Param1:01-02-2019 | Param2:01-02-2019 | … |
+--------+------------+-----------+-------------------+-------------------+-------------------+-------------------+---+
| 1 | Snow | John | Text1 | Text1 | Text3 | Text2 | … |
| 2 | Lannister | Tyrion | Text1 | Text1 | Text3 | Text2 | … |
| 3 | Targaryen | Daenerys | Text2 | Text2 | Text3 | Text3 | … |
+--------+------------+-----------+-------------------+-------------------+-------------------+-------------------+---+
所以,基本上,我试图解决2个问题:
注意:Param1
和Param2
列具有预定义的值(每个大约10个)
我的启动静态数据透视查询是这样的:
WITH PivotData AS
(
SELECT
[UserId]
,[Last Name]
,[First Name]
,[Param1]
,[Param2]
,[Date]
FROM [dbo].[MyTable]
)
SELECT [Last Name], [First Name], [Param1:01-01-2019], [Param2:01-01-2019], [Param1:01-02-2019], [Param2:01-02-2019]
FROM PivotData
PIVOT ( MAX([Param1]) FOR [Date] in ([Param1:01-01-2019], [Param1:01-01-2019]) ) AS P1
PIVOT ( MAX([Param2) FOR [Date] in ([Param2:01-02-2019], [Param2:01-02-2019]) ) AS P2
更新1:
我已经使用了另一个查询,但仍需要动态执行,因此原始问题仍然存在
SELECT
[UserId]
MAX(CASE WHEN [Date] = '2019-01-01' THEN ISNULL([Param1], NULL) ELSE NULL END) AS [Param1:2019-01-01],
MAX(CASE WHEN [Date] = '2019-01-01' THEN ISNULL([Param2], NULL) ELSE NULL END) AS [Param2:2019-01-01],
MAX(CASE WHEN [Date] = '2019-01-01' THEN ISNULL([Param3], NULL) ELSE NULL END) AS [Param3:2019-01-01],
MAX(CASE WHEN [Date] = '2019-01-02' THEN ISNULL([Param1], NULL) ELSE NULL END) AS [Param1:2019-01-02],
MAX(CASE WHEN [Date] = '2019-01-02' THEN ISNULL([Param2], NULL) ELSE NULL END) AS [Param2:2019-01-02],
MAX(CASE WHEN [Date] = '2019-01-02' THEN ISNULL([Param3], NULL) ELSE NULL END) AS [Param3:2019-01-02],
FROM [dbo].[MyTable]
GROUP BY [UserId]
ORDER BY [UserId]
但逻辑仍然让我感到困惑。请帮忙。
此查询将创建120个日期的列表,然后生成所请求的列组。
DECLARE @SQL NVARCHAR(MAX);
WITH
E(n) AS( --11 rows
SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0))E(n)
),
E2(n) AS( --11x11= 121 rows
SELECT a.n FROM E a, E b
),
cteTally(calDate) AS(
SELECT TOP( 120)
DATEADD( dd, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) -1, '20190101') calDate
FROM E2
)
SELECT @SQL =
--Identify first static part of query. Columns that won't be pivoted.
N'SELECT [UserId]'
--Identify the dynamic part and set the pattern. Use FOR XML PATH to concatenate the values.
+ ( SELECT N'
,MAX(CASE WHEN [Date] = ''' + CONVERT( NCHAR(8), calDate, 112) + ''' THEN ISNULL([Param1], NULL) ELSE NULL END) AS [Param1:' + CONVERT( NCHAR(10), calDate, 120) + ']
,MAX(CASE WHEN [Date] = ''' + CONVERT( NCHAR(8), calDate, 112) + ''' THEN ISNULL([Param2], NULL) ELSE NULL END) AS [Param2:' + CONVERT( NCHAR(10), calDate, 120) + ']
,MAX(CASE WHEN [Date] = ''' + CONVERT( NCHAR(8), calDate, 112) + ''' THEN ISNULL([Param3], NULL) ELSE NULL END) AS [Param3:' + CONVERT( NCHAR(10), calDate, 120) + ']'
FROM cteTally
FOR XML PATH(''), TYPE).value('./text()[1]', 'nvarchar(max)')
--Identify second static part of query. Everything starting with the FROM clause.
+ N'FROM [dbo].[MyTable]
GROUP BY [UserId]
ORDER BY [UserId];
DECLARE @SQL NVARCHAR(MAX);'
--Used for debugging purposes
PRINT @SQL
--Execute the dynamic query. Use parameters when needed.
EXEC sp_executesql @SQL --, @ParamDefinition, @Param1, @Param2, ..., @ParamN;
GO
如评论中提到的那样,您需要使用动态SQL。根据您的(小)样本,这是有效的,如果您需要对其进行任何更改以满足您的需求,则由您决定。 PRINT
声明是你的朋友(如果你有超过4,000个字符,你可能需要更改为SELECT
):
CREATE TABLE dbo.SampleTable (UserId int,
LastName varchar(50),
FirstName varchar(50),
Param1 varchar(6),
Param2 varchar(6),
[Date] date);
GO
INSERT INTO dbo.SampleTable
VALUES (1,'Snow','John','Text1','Text1','20190101'),
(2,'Lannister','Tyrion','Text1','Text1','20190101'),
(3,'Targaryen','Daenerys','Text2','Text2','20190101'),
(1,'Snow','John','Text3','Text2','20190102'),
(2,'Lannister','Tyrion','Text3','Text2','20190102'),
(3,'Targaryen','Daenerys','Text3','Text3','20190102');
GO
DECLARE @SQL nvarchar(MAX);
SET @SQL = N'SELECT UserId,' + NCHAR(13) + NCHAR(10) +
STUFF((SELECT N',' + NCHAR(13) + NCHAR(10) +
N' MAX(CASE [Date] WHEN ' + QUOTENAME(CONVERT(varchar(8),ST.[Date],112),'''') + N' THEN ' + QUOTENAME(C.COLUMN_NAME) + N' END) AS ' + QUOTENAME(C.COLUMN_NAME + N':' + REPLACE(CONVERT(varchar(10),ST.[Date],102),N'.',N'-'))
FROM INFORMATION_SCHEMA.COLUMNS C
CROSS JOIN (SELECT DISTINCT [Date]
FROM dbo.SampleTable) ST
WHERE C.TABLE_SCHEMA = N'dbo'
AND C.TABLE_NAME = N'SampleTable'
AND C.COLUMN_NAME LIKE N'Param%'
ORDER BY ST.[Date],
C.ORDINAL_POSITION
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,3,N'') + NCHAR(13) + NCHAR(10) +
N'FROM dbo.SampleTable' + NCHAR(13) + NCHAR(10) +
N'GROUP BY UserId' + NCHAR(13) + NCHAR(10) +
N'ORDER BY UserId;';
PRINT @SQL; --Your Debugging best friend
EXEC sp_executesql @SQL;
GO
DROP TABLE SampleTable