如何在 SQL 服务器中加入两个动态数据透视表(table 数据透视表后的数据)
How to join two dynamic pivot(table data after pivot) in SQL Server
说明
我有一个 table 并且我对它们的 table 进行了透视,以便只获得 1 table 的所有数据。我附上了一张图片,其中包含我拥有的 table 和我想要得到的结果。
Table:
使用下面的查询进行动态数据透视后,我们将根据需要获得记录,但分为两个 table
DECLARE @cols nvarchar(max)
DECLARE @cols1 nvarchar(max)
DECLARE @stmt nvarchar(max)
DECLARE @stmt1 nvarchar(max)
SELECT @cols = STRING_AGG(QUOTENAME([YearMonth]), ',') WITHIN GROUP (ORDER BY [YearMonth])
FROM (
SELECT REPLACE(RIGHT(CONVERT(VARCHAR(9), CreatedOn, 6), 6), ' ', '/') AS [YearMonth]
FROM [dbo].[TblDemoData]
UNION
SELECT NULL
WHERE 1 = 0
) t
SELECT @cols1 = STRING_AGG(QUOTENAME([YearMonth1]), ',') WITHIN GROUP (ORDER BY [YearMonth1])
FROM (
SELECT REPLACE(RIGHT(CONVERT(VARCHAR(9), CreatedOn, 6), 6), ' ', '_') AS [YearMonth1]
FROM [dbo].[TblDemoData]
UNION
SELECT NULL
WHERE 1 = 0
) t1
print @cols1
SELECT * INTO #Data
FROM
(
select AgentId,
case
when sum( MaximumScore)=0
then 0
else
sum(ISNULL(AchievedScore,0)*100)/sum(ISNULL(MaximumScore,0))
end as Score,
COUNT(T.Id) as NumberOfAudit,
REPLACE(RIGHT(CONVERT(VARCHAR(9), T.CreatedOn, 6), 6), ' ', '/') AS [YearMonth]
from [dbo].[TblDemoData] T
where T.AgentId=49
group by AgentId,REPLACE(RIGHT(CONVERT(VARCHAR(9), T.CreatedOn, 6), 6), ' ', '/')
)TAB
SELECT * INTO #Data1
FROM
(
select T.AgentId,
case
when sum( MaximumScore)=0
then 0
else
sum(ISNULL(AchievedScore,0)*100)/sum(ISNULL(MaximumScore,0))
end as Score,
COUNT(T.Id) as NumberOfAudit,
REPLACE(RIGHT(CONVERT(VARCHAR(9), T.CreatedOn, 6), 6), ' ', '_') AS [YearMonth1]
from [dbo].[TblDemoData] T
where T.AgentId=49
group by T.AgentId,REPLACE(RIGHT(CONVERT(VARCHAR(9), T.CreatedOn, 6), 6), ' ', '_')
)TAB
SELECT @stmt =
'SELECT * from
(
SELECT AgentId,NumberOfAudit, YearMonth FROM #Data
) x
PIVOT
(
sum(NumberOfAudit)
FOR [YearMonth] IN (' + @cols + ')
) as p1
SELECT * from
(
SELECT AgentId,Score, YearMonth1 FROM #Data1
) x
PIVOT
(
sum(Score)
FOR [YearMonth1] IN (' + @cols1 + ')
) as p2
'
exec sp_executesql @stmt
上述查询的输出
我们的需要
TABLE 有数据
CREATE TABLE [dbo].[TblDemoData](
[Id] [int] IDENTITY(1,1) NOT NULL,
[AgentId] [int] NULL,
[MaximumScore] [int] NULL,
[AchievedScore] [int] NULL,
[CreatedOn] [datetime] NULL,
CONSTRAINT [PK_TblDemoData] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[TblDemoData] ON
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (1, 49, 110, 110, CAST(N'2021-11-01T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (2, 49, 102, 99, CAST(N'2021-11-02T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (3, 49, 110, 102, CAST(N'2021-11-09T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (4, 49, 102, 102, CAST(N'2021-11-17T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (5, 49, 105, 105, CAST(N'2021-11-17T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (6, 49, 89, 89, CAST(N'2021-11-24T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (7, 49, 102, 102, CAST(N'2021-10-05T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (8, 49, 102, 102, CAST(N'2021-10-07T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (9, 49, 102, 102, CAST(N'2021-10-15T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (10, 49, 102, 102, CAST(N'2021-10-18T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (11, 49, 118, 118, CAST(N'2021-10-19T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (12, 49, 102, 102, CAST(N'2021-10-26T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (13, 49, 84, 79, CAST(N'2021-10-26T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (14, 49, 96, 0, CAST(N'2022-01-21T13:10:00.000' AS DateTime))
GO
SET IDENTITY_INSERT [dbo].[TblDemoData] OFF
GO
老实说,这应该是您的表示层而不是 SQL 层;特别是当你想要合并单元格时(SQL 中不存在的概念)。
我个人会切换到条件聚合,而不是限制性的 PIVOT
运算符,然后执行如下操作:
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = NCHAR(13) + NCHAR(10);
DECLARE @Delimiter nchar(3) = N',' + @CRLF;
WITH DateRanges AS(
SELECT DISTINCT
DATEADD(MONTH, DATEDIFF(MONTH,0,CreatedOn),0) AS StartDate,
DATEADD(MONTH, DATEDIFF(MONTH,0,CreatedOn)+1,0) AS EndDate
FROM dbo.TblDemoData)
SELECT @SQL = N'SELECT DD.AgentID,' + @CRLF +
STRING_AGG(N' COUNT(CASE WHEN DD.CreatedOn >= ' + QUOTENAME(CONVERT(varchar(8),DR.StartDate,112),'''') + N' AND DD.CreatedOn < ' + QUOTENAME(CONVERT(varchar(8),DR.EndDate,112),'''') + N' THEN 1 END) AS ' + QUOTENAME(CONCAT(YEAR(DR.StartDate),'-',DATENAME(MONTH,DR.StartDate),N'-Audits')) + N',' + @CRLF +
N' SUM(CASE WHEN DD.CreatedOn >= ' + QUOTENAME(CONVERT(varchar(8),DR.StartDate,112),'''') + N' AND DD.CreatedOn < ' + QUOTENAME(CONVERT(varchar(8),DR.EndDate,112),'''') + N' THEN AchievedScore* 1. ELSE 0 END) / ' + @CRLF +
N' SUM(CASE WHEN DD.CreatedOn >= ' + QUOTENAME(CONVERT(varchar(8),DR.StartDate,112),'''') + N' AND DD.CreatedOn < ' + QUOTENAME(CONVERT(varchar(8),DR.EndDate,112),'''') + N' THEN MaximumScore ELSE 0 END) AS ' + QUOTENAME(CONCAT(YEAR(DR.StartDate),'-',DATENAME(MONTH,DR.StartDate),N'-Score')),@Delimiter) WITHIN GROUP (ORDER BY DR.StartDate) + @CRLF +
N'FROM dbo.TblDemoData DD' + @CRLF +
N'GROUP BY DD.AgentId;'
FROM DateRanges DR;
--PRINT @SQL; Your debugging best friend
EXEC sys.sp_executesql @SQL;
请注意,这不会按照您要求的顺序给出列,但是,列的顺序没有意义,并且(再次)应该在您的表示层中进行控制。
说明
我有一个 table 并且我对它们的 table 进行了透视,以便只获得 1 table 的所有数据。我附上了一张图片,其中包含我拥有的 table 和我想要得到的结果。
Table:
使用下面的查询进行动态数据透视后,我们将根据需要获得记录,但分为两个 table
DECLARE @cols nvarchar(max)
DECLARE @cols1 nvarchar(max)
DECLARE @stmt nvarchar(max)
DECLARE @stmt1 nvarchar(max)
SELECT @cols = STRING_AGG(QUOTENAME([YearMonth]), ',') WITHIN GROUP (ORDER BY [YearMonth])
FROM (
SELECT REPLACE(RIGHT(CONVERT(VARCHAR(9), CreatedOn, 6), 6), ' ', '/') AS [YearMonth]
FROM [dbo].[TblDemoData]
UNION
SELECT NULL
WHERE 1 = 0
) t
SELECT @cols1 = STRING_AGG(QUOTENAME([YearMonth1]), ',') WITHIN GROUP (ORDER BY [YearMonth1])
FROM (
SELECT REPLACE(RIGHT(CONVERT(VARCHAR(9), CreatedOn, 6), 6), ' ', '_') AS [YearMonth1]
FROM [dbo].[TblDemoData]
UNION
SELECT NULL
WHERE 1 = 0
) t1
print @cols1
SELECT * INTO #Data
FROM
(
select AgentId,
case
when sum( MaximumScore)=0
then 0
else
sum(ISNULL(AchievedScore,0)*100)/sum(ISNULL(MaximumScore,0))
end as Score,
COUNT(T.Id) as NumberOfAudit,
REPLACE(RIGHT(CONVERT(VARCHAR(9), T.CreatedOn, 6), 6), ' ', '/') AS [YearMonth]
from [dbo].[TblDemoData] T
where T.AgentId=49
group by AgentId,REPLACE(RIGHT(CONVERT(VARCHAR(9), T.CreatedOn, 6), 6), ' ', '/')
)TAB
SELECT * INTO #Data1
FROM
(
select T.AgentId,
case
when sum( MaximumScore)=0
then 0
else
sum(ISNULL(AchievedScore,0)*100)/sum(ISNULL(MaximumScore,0))
end as Score,
COUNT(T.Id) as NumberOfAudit,
REPLACE(RIGHT(CONVERT(VARCHAR(9), T.CreatedOn, 6), 6), ' ', '_') AS [YearMonth1]
from [dbo].[TblDemoData] T
where T.AgentId=49
group by T.AgentId,REPLACE(RIGHT(CONVERT(VARCHAR(9), T.CreatedOn, 6), 6), ' ', '_')
)TAB
SELECT @stmt =
'SELECT * from
(
SELECT AgentId,NumberOfAudit, YearMonth FROM #Data
) x
PIVOT
(
sum(NumberOfAudit)
FOR [YearMonth] IN (' + @cols + ')
) as p1
SELECT * from
(
SELECT AgentId,Score, YearMonth1 FROM #Data1
) x
PIVOT
(
sum(Score)
FOR [YearMonth1] IN (' + @cols1 + ')
) as p2
'
exec sp_executesql @stmt
上述查询的输出
我们的需要
TABLE 有数据
CREATE TABLE [dbo].[TblDemoData](
[Id] [int] IDENTITY(1,1) NOT NULL,
[AgentId] [int] NULL,
[MaximumScore] [int] NULL,
[AchievedScore] [int] NULL,
[CreatedOn] [datetime] NULL,
CONSTRAINT [PK_TblDemoData] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[TblDemoData] ON
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (1, 49, 110, 110, CAST(N'2021-11-01T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (2, 49, 102, 99, CAST(N'2021-11-02T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (3, 49, 110, 102, CAST(N'2021-11-09T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (4, 49, 102, 102, CAST(N'2021-11-17T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (5, 49, 105, 105, CAST(N'2021-11-17T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (6, 49, 89, 89, CAST(N'2021-11-24T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (7, 49, 102, 102, CAST(N'2021-10-05T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (8, 49, 102, 102, CAST(N'2021-10-07T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (9, 49, 102, 102, CAST(N'2021-10-15T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (10, 49, 102, 102, CAST(N'2021-10-18T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (11, 49, 118, 118, CAST(N'2021-10-19T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (12, 49, 102, 102, CAST(N'2021-10-26T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (13, 49, 84, 79, CAST(N'2021-10-26T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[TblDemoData] ([Id], [AgentId], [MaximumScore], [AchievedScore], [CreatedOn]) VALUES (14, 49, 96, 0, CAST(N'2022-01-21T13:10:00.000' AS DateTime))
GO
SET IDENTITY_INSERT [dbo].[TblDemoData] OFF
GO
老实说,这应该是您的表示层而不是 SQL 层;特别是当你想要合并单元格时(SQL 中不存在的概念)。
我个人会切换到条件聚合,而不是限制性的 PIVOT
运算符,然后执行如下操作:
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = NCHAR(13) + NCHAR(10);
DECLARE @Delimiter nchar(3) = N',' + @CRLF;
WITH DateRanges AS(
SELECT DISTINCT
DATEADD(MONTH, DATEDIFF(MONTH,0,CreatedOn),0) AS StartDate,
DATEADD(MONTH, DATEDIFF(MONTH,0,CreatedOn)+1,0) AS EndDate
FROM dbo.TblDemoData)
SELECT @SQL = N'SELECT DD.AgentID,' + @CRLF +
STRING_AGG(N' COUNT(CASE WHEN DD.CreatedOn >= ' + QUOTENAME(CONVERT(varchar(8),DR.StartDate,112),'''') + N' AND DD.CreatedOn < ' + QUOTENAME(CONVERT(varchar(8),DR.EndDate,112),'''') + N' THEN 1 END) AS ' + QUOTENAME(CONCAT(YEAR(DR.StartDate),'-',DATENAME(MONTH,DR.StartDate),N'-Audits')) + N',' + @CRLF +
N' SUM(CASE WHEN DD.CreatedOn >= ' + QUOTENAME(CONVERT(varchar(8),DR.StartDate,112),'''') + N' AND DD.CreatedOn < ' + QUOTENAME(CONVERT(varchar(8),DR.EndDate,112),'''') + N' THEN AchievedScore* 1. ELSE 0 END) / ' + @CRLF +
N' SUM(CASE WHEN DD.CreatedOn >= ' + QUOTENAME(CONVERT(varchar(8),DR.StartDate,112),'''') + N' AND DD.CreatedOn < ' + QUOTENAME(CONVERT(varchar(8),DR.EndDate,112),'''') + N' THEN MaximumScore ELSE 0 END) AS ' + QUOTENAME(CONCAT(YEAR(DR.StartDate),'-',DATENAME(MONTH,DR.StartDate),N'-Score')),@Delimiter) WITHIN GROUP (ORDER BY DR.StartDate) + @CRLF +
N'FROM dbo.TblDemoData DD' + @CRLF +
N'GROUP BY DD.AgentId;'
FROM DateRanges DR;
--PRINT @SQL; Your debugging best friend
EXEC sys.sp_executesql @SQL;
请注意,这不会按照您要求的顺序给出列,但是,列的顺序没有意义,并且(再次)应该在您的表示层中进行控制。