0

我正在尝试根据时间戳获取数据的轴心。我想把它们分成半小时的“桶”。例如,使用以下数据:

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 WHEN 的情况下做到这一点?

谢谢!

4

2 回答 2

2

也许我正在尝试解决一个不存在的问题,但我想提供一个替代解决方案,该解决方案在员工数量方面是动态的(它为额外的员工添加了列)并将每个时间段内的销售金额相加员工,如果该时段内有不止一项销售;如果您不汇总金额,那么您最终会在某人已售出不止一次的每个时间段中出现多行。

时隙生成是从 Nenads answer 中的优秀解决方案中借用的。

首先是带有几行额外行的测试数据来说明差异:

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)
于 2013-07-24T13:44:29.160 回答
1

您可以使用递归 CTE 来“即时”创建您的时隙,然后将其加入您的数据中。有一种方法可以避免使用CASE,您可以使用PIVOTcommand 代替,但我认为这要简单得多:

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

SQLFiddle 演示

于 2013-07-24T11:28:33.963 回答