2013-07-24 3 views
0

Я пытаюсь получить стержень своих данных на основе метки времени. Я хочу сгруппировать их в полчаса «ведра». Например, с данными ниже:SQL Сводные данные по времени

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?

Спасибо!

+0

находка от этой ссылки [1]: http://stackoverflow.com/questions/17668504/how-to-generate-this-sql-query-like-pivot-table#autocomment25736660 – Vijay

ответ

2

Может быть, я пытаюсь решить несуществующую проблему но я хотел бы предложить альтернативное решение, которое является динамичным по отношению к числу сотрудников (оно добавляет столбцы для дополнительных сотрудников) и суммирует суммы, проданные в временном интервале на одного сотрудника, если в этом слоте имеется более одной продажи; если вы не суммируете сумму, вы получите несколько строк для каждого временного интервала, где кто-то продал его более одного раза.

Создание временных интервалов заимствовано из отличного решения в ответе 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) 
+0

это замечательно! Я не знал о функции CTE в mssql до сих пор .. был на грани написания курсора, чтобы сделать это вместо этого. спасибо jpw! – d0h

+0

@ d0h Рад помочь. [Обычные табличные выражения] (http://msdn.microsoft.com/en-us/library/ms190766%28v=sql.105%29.aspx) могут быть действительно мощными и заслуживают внимания. – jpw

1

Вы можете использовать рекурсивный CTE для создания временных интервалов «на лету», а затем присоединиться к ним к вашим данным. Существует способ избежать использования CASE, вы можете использовать PIVOT команду вместо этого, но я думаю, что это гораздо проще:

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 DEMO

+0

спасибо Ненаду, но ответ jpw выше d ynamically создает столбцы для сотрудников без необходимости CASE! – d0h

Смежные вопросы