按时间划分的SQL数据透视
我试图根据时间戳获取数据的轴心。我想把它们分成半小时的桶。例如,使用以下数据:按时间划分的SQL数据透视,sql,sql-server-2008,tsql,Sql,Sql Server 2008,Tsql,我试图根据时间戳获取数据的轴心。我想把它们分成半小时的桶。例如,使用以下数据: CREATE TABLE #test ( Employee nvarchar(20) NOT NULL ,[SaleTime] time NOT NULL ,Amount float NOT NULL ) INSERT INTO #test VALUES ('A', '08:10', '100.50') ,('A', '12:20', '758.23') ,('A', '11:59', '
CREATE TABLE #test (
Employee nvarchar(20) NOT NULL
,[SaleTime] time NOT NULL
,Amount float NOT NULL
)
INSERT INTO #test VALUES
('A', '08:10', '100.50')
,('A', '12:20', '758.23')
,('A', '11:59', '592.11')
,('B', '12:00', '95.00')
,('B', '09:01', '29.10')
,('B', '09:04', '53.22')
,('C', '11:23', '55.77')
,('C', '10:40', '128.00')
我希望结果是这样的
Time | A | B | C |
-----------------------------------------------------------------
08:00 - 08:30 | 100.5 | | |
08:30 - 09:00 | | | |
09:00 - 09:30 | | 82.32 | |
09:30 - 10:00 | | | |
10:00 - 10:30 | | | |
10:30 - 11:00 | | | 128.00 |
11:00 - 11:30 | | | 55.77 |
11:30 - 12:00 | 592.11 | | |
12:00 - 12:30 | 758.23 | 95.00 | |
12:30 - 13:00 | | | |
-----------------------------------------------------------------
我是否必须创建一个带有时间段的空表才能这样做?有没有一种不使用CASE的方法
谢谢 您可以使用递归CTE“动态”创建时间段,然后将其加入到数据中。有一种方法可以避免使用CASE,您可以改用command,但我认为这要简单得多:
WITH CTE_TimeSlots AS
(
SELECT CAST('8:00' AS TIME) AS StartTime, CAST('8:30' AS TIME) AS EndTime
UNION ALL
SELECT DATEADD(MI, 30, StartTime), DATEADD(MI, 30, EndTime)
FROM CTE_TimeSlots
WHERE StartTime <= '12:00'
)
SELECT CONVERT(NVARCHAR(10),StartTime) + ' - ' + CONVERT(NVARCHAR(10),EndTime) AS [Time]
, CASE WHEN Employee = 'A' THEN Amount END AS A
, CASE WHEN Employee = 'B' THEN Amount END AS B
, CASE WHEN Employee = 'C' THEN Amount END AS C
FROM CTE_TimeSlots t
LEFT JOIN #test d ON d.SaleTime >= StartTime AND d.SaleTime < EndTime
您可以使用递归CTE“动态”创建时间段,然后将其加入到数据中。有一种方法可以避免使用CASE,您可以改用command,但我认为这要简单得多:
WITH CTE_TimeSlots AS
(
SELECT CAST('8:00' AS TIME) AS StartTime, CAST('8:30' AS TIME) AS EndTime
UNION ALL
SELECT DATEADD(MI, 30, StartTime), DATEADD(MI, 30, EndTime)
FROM CTE_TimeSlots
WHERE StartTime <= '12:00'
)
SELECT CONVERT(NVARCHAR(10),StartTime) + ' - ' + CONVERT(NVARCHAR(10),EndTime) AS [Time]
, CASE WHEN Employee = 'A' THEN Amount END AS A
, CASE WHEN Employee = 'B' THEN Amount END AS B
, CASE WHEN Employee = 'C' THEN Amount END AS C
FROM CTE_TimeSlots t
LEFT JOIN #test d ON d.SaleTime >= StartTime AND d.SaleTime < EndTime
也许我试图解决一个不存在的问题,但我想提供一个替代解决方案,该解决方案在员工数量方面是动态的,它为额外的员工添加列,并对每个员工在一个时间段内的销售金额进行合计,如果该时间段内有多个销售;如果你不合计金额,你将得到多行的时间段,其中有人已经卖出了不止一次 时隙生成借鉴了Nenads答案中的优秀解决方案 首先,使用两个额外的行显示测试数据,以说明差异:
DROP TABLE #test;
CREATE TABLE #test (
Employee nvarchar(20) NOT NULL
,[SaleTime] time NOT NULL
,Amount float NOT NULL
)
INSERT INTO #test VALUES
('A', '08:10', '100.50')
,('A', '12:20', '758.23')
,('A', '11:59', '592.11')
,('B', '12:00', '95.00')
,('B', '09:01', '29.10')
,('B', '09:04', '53.22')
,('C', '11:23', '55.77')
,('C', '10:40', '128.00')
,('D', '09:40', '28.00')
,('E', '11:40', '50.00')
,('E', '11:35', '20.00')
查询动态生成SQL语句并使用EXECUTE语句执行:
DECLARE @Headers VARCHAR(MAX)
SELECT @Headers = COALESCE(@Headers + ',[' + Employee + ']', '[' + Employee + ']')
FROM (SELECT DISTINCT Employee FROM #test) Emp
DECLARE @SQL NVARCHAR(MAX)
SET @SQL = N'
WITH CTE_TimeSlots AS
(
SELECT CAST(''8:00'' AS TIME) AS StartTime, CAST(''8:30'' AS TIME) AS EndTime
UNION ALL
SELECT DATEADD(MI, 30, StartTime), DATEADD(MI, 30, EndTime)
FROM CTE_TimeSlots
WHERE StartTime <= ''12:00''
)
SELECT * FROM (
SELECT CONVERT(NVARCHAR(10),StartTime) + '' - '' + CONVERT(NVARCHAR(10),EndTime) AS [Time], Amount, Employee
FROM CTE_TimeSlots t
LEFT JOIN #test d ON d.SaleTime >= StartTime AND d.SaleTime < EndTime
) innerQuery
PIVOT (SUM(Amount) FOR Employee IN (' + @Headers + ')
) AS PivotTable
'
--PRINT @SQL -- Uncomment to see the query which will be run
EXECUTE(@SQL)
也许我试图解决一个不存在的问题,但我想提供一个替代解决方案,该解决方案在员工数量方面是动态的,它为额外的员工添加列,并对每个员工在一个时间段内的销售金额进行合计,如果该时间段内有多个销售;如果你不合计金额,你将得到多行的时间段,其中有人已经卖出了不止一次 时隙生成借鉴了Nenads答案中的优秀解决方案 首先,使用两个额外的行显示测试数据,以说明差异:
DROP TABLE #test;
CREATE TABLE #test (
Employee nvarchar(20) NOT NULL
,[SaleTime] time NOT NULL
,Amount float NOT NULL
)
INSERT INTO #test VALUES
('A', '08:10', '100.50')
,('A', '12:20', '758.23')
,('A', '11:59', '592.11')
,('B', '12:00', '95.00')
,('B', '09:01', '29.10')
,('B', '09:04', '53.22')
,('C', '11:23', '55.77')
,('C', '10:40', '128.00')
,('D', '09:40', '28.00')
,('E', '11:40', '50.00')
,('E', '11:35', '20.00')
查询动态生成SQL语句并使用EXECUTE语句执行:
DECLARE @Headers VARCHAR(MAX)
SELECT @Headers = COALESCE(@Headers + ',[' + Employee + ']', '[' + Employee + ']')
FROM (SELECT DISTINCT Employee FROM #test) Emp
DECLARE @SQL NVARCHAR(MAX)
SET @SQL = N'
WITH CTE_TimeSlots AS
(
SELECT CAST(''8:00'' AS TIME) AS StartTime, CAST(''8:30'' AS TIME) AS EndTime
UNION ALL
SELECT DATEADD(MI, 30, StartTime), DATEADD(MI, 30, EndTime)
FROM CTE_TimeSlots
WHERE StartTime <= ''12:00''
)
SELECT * FROM (
SELECT CONVERT(NVARCHAR(10),StartTime) + '' - '' + CONVERT(NVARCHAR(10),EndTime) AS [Time], Amount, Employee
FROM CTE_TimeSlots t
LEFT JOIN #test d ON d.SaleTime >= StartTime AND d.SaleTime < EndTime
) innerQuery
PIVOT (SUM(Amount) FOR Employee IN (' + @Headers + ')
) AS PivotTable
'
--PRINT @SQL -- Uncomment to see the query which will be run
EXECUTE(@SQL)
从该链接中查找引用[1]:从该链接中查找引用[1]:谢谢Nenad,但是jpw上面的回答动态地为员工创建列,而不需要CASE!感谢Nenad,但是jpw上面的回答动态地为员工创建列,而不需要CASE!这太完美了!到目前为止,我还不知道mssql中的CTE函数。。即将编写一个游标来执行此操作。谢谢你,jpw@我很乐意帮忙。它真的很强大,值得进一步研究。这太完美了!到目前为止,我还不知道mssql中的CTE函数。。即将编写一个游标来执行此操作。谢谢你,jpw@我很乐意帮忙。可以真正强大,值得进一步研究。