如何将行旋转为列,并按过去 7 天显示 - SQL SERVER

Posted

技术标签:

【中文标题】如何将行旋转为列,并按过去 7 天显示 - SQL SERVER【英文标题】:How to pivot Rows as columns, and show by the last 7 days - SQL SERVER 【发布时间】:2020-12-18 11:09:46 【问题描述】:

我正在尝试获取过去 7 天(不包括今天)的员工时间

我有一个看起来像这样的结果表

|EmpID | Date       | Totaltime|
|------|------------|----------|
|1001  | 2020-12-17 |   1000   | 
|1001  | 2020-12-16 |   2641   |
|1001  | 2020-12-14 |   1532   |

我需要将日期行作为从第 1 天(昨天)到第 7 天(8 天前)倒退的列

结果应该是这样的:

|EmpID | Day1 | Day2 | Day3 | Day4 | Day5 | Day6 | Day7 |
|------|------|------|------|------|------|------|------|
|1001  | 1000 | 2641 |      | 1532 |      |      |      |

如您所见,Day3、Day5、Day6、Day7 是空的,因为它们没有值。

我似乎找不到实现这一目标的快速方法。 PIVOT 功能需要您硬编码不适合的日期,因为我并不总是知道日期。

【问题讨论】:

【参考方案1】:

您可以像这样使用日期算术和条件聚合:

select empid,
    max(case when date = dateadd(day, -1, convert(date, getdate())) then totaltime end) as day1,
    max(case when date = dateadd(day, -2, convert(date, getdate())) then totaltime end) as day2,
    ...
from mytable
group by empid

【讨论】:

【参考方案2】:

给你,这是一个始终使用过去 7 天的动态数据透视表。如果您希望输出为第 1 天、第 2 天、第 3 天等,并且不知道如何自己执行此操作,我可以编辑查询。此外,正如您在输出中看到的那样,如果您不想要总和,只需将其更改为 MAX,这将重新计算总和 od Totaltime。

DROP TABLE IF EXISTS #tbl;
CREATE TABLE #tbl(EmpId int, [Date] date, Totaltime int);

INSERT INTO #tbl(EmpId, [Date], Totaltime)
VALUES (1001 , '2020-12-17' ,  1000)
,(1001 , '2020-12-16' ,  241) 
,(1001 , '2020-12-14' ,  1532)
,(1002 , '2020-12-17' ,  100)
,(1002 , '2020-12-16' ,  23641) 
,(1003 , '2020-12-14' ,  153)
,(1003 , '2020-12-11' ,  200)
,(1003 , '2020-12-11' ,  300);



DECLARE @sql  nvarchar(max);
DECLARE @columnname nvarchar(max);


;with cte as
(SELECT dateadd(day,-1,CAST(GETDATE() AS date)) AS dt
UNION ALL
SELECT dateadd(day,-1,cte.dt)
FROM cte
WHERE cte.dt>dateadd(day,-7,CAST(GETDATE() AS date))
)
SELECT @columnname=COALESCE(@columnname+ ',', '') + QUOTENAME(CAST(cte.dt AS nvarchar(20)),'[]')
FROM cte;

/*USE MAX INSTEAD OF SUM BELOW IF YOU JUST WANT VALUES AND NOT A SUM*/
SET @sql='
SELECT *
FROM #tbl t
PIVOT
(SUM(TotalTime)
FOR [Date] IN('+@columnname+')) AS p'

EXECUTE sp_executesql @sql

输出:

【讨论】:

【参考方案3】:

与另一个答案类似,这是一个动态脚本,它将始终抓取前 7 天并以它们为中心。它建立一个带有相关日期的临时表,string_agg 将它们放入一条记录中,然后将其传递给动态数据透视表。

DROP TABLE IF EXISTS #tbl;
CREATE TABLE #tbl(EmpId int, [Date] date, Totaltime int);

INSERT INTO #tbl(EmpId, [Date], Totaltime)
VALUES (1001 , '2020-12-17' ,  1000)
,(1001 , '2020-12-16' ,  241) 
,(1001 , '2020-12-14' ,  1532)
,(1002 , '2020-12-17' ,  100)
,(1002 , '2020-12-16' ,  23641) 
,(1003 , '2020-12-14' ,  153)
,(1003 , '2020-12-11' ,  200)
,(1003 , '2020-12-11' ,  300);

DECLARE @Date DATE
SET @Date = DATEADD(DAY,-7,GETDATE())

DROP TABLE IF EXISTS #Date
CREATE TABLE #Date (Date DATE)

WHILE @Date <= DATEADD(DAY,-1,GETDATE())
BEGIN
    INSERT INTO #Date VALUES (@Date)
    SET @Date = DATEADD(DAY,1,@Date)
END

DECLARE @PivotDate VARCHAR(MAX)

SELECT 
@PivotDate = STRING_AGG(CONCAT('[',Date,']'),',') 
FROM #Date

DECLARE @SQL NVARCHAR(MAX)

SET @SQL = 
'
SELECT
*
FROM #tbl
PIVOT
(
    MAX(Totaltime)
    FOR Date IN (' + @PivotDate + ')
) p'

EXEC sys.sp_executesql @SQL

【讨论】:

以上是关于如何将行旋转为列,并按过去 7 天显示 - SQL SERVER的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 动态地将行转为列

在 Oracle 中动态地将行转为列

使用 Laravel 查询数据并按天分组

SQL(横表和纵表)行列转换,PIVOT与UNPIVOT的区别和使用方法举例

将行名转换为列名,并按日期求和并显示数据

PHP如何将SQL查询结果转为多维数组,并按查询行输出