Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
按时间划分的SQL数据透视_Sql_Sql Server 2008_Tsql - Fatal编程技术网

按时间划分的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@我很乐意帮忙。可以真正强大,值得进一步研究。