2015-07-30 3 views
2

У меня есть простой запрос, какие группы и заказы Дата данные:заказа дт в год и дату, когда несколько месяцев отсутствуют

SELECT COUNT(*) AS Events, 
     datepart(YYYY, call_date) AS YearPart, 
     datepart(MM, call_date) As MonthPart, 
     datename(YYYY, call_date) AS YearName, 
     dateName(MM, call_date) As MonthName 
FROM rm_report 
GROUP BY 
    datename(year, call_date), 
    datename(month, call_date), 
    datepart(year, call_date), 
    datepart(month, call_date) 
ORDER BY 
    YearPart, 
    MonthPart; 

Вопрос заключается в том, что первые два месяца первого года не содержат никаких данных. В результате заказа начинается на третьем месяце, а затем циклы первого

EVENTS | YEARPART | YEARNAME | MONTHPART | MONTHNAME 
3  2012  2012  3   March 
6  2012  2012  4   April 
6  2012  2012  5   May 
6  2012  2012  6   June 
6  2012  2012  7   July 
6  2012  2012  8   August 
6  2012  2012  9   September 
6  2012  2012  10   October 
6  2012  2012  11   November 
6  2012  2012  12   December 
6  2012  2013  1   January 
6  2012  2013  2   February 

Как я могу гарантировать, что если нет никаких событий, а 0 выделяется, так что список может быть в правильном порядке - то есть первая запись в столбце MonthPart равна «1», а первая запись в столбце YearPart - 2012 год?

Мы используем MS SQL.

+0

Поиск таблицы календаря – Mihai

+0

Вставьте несколько фиктивных строк и проверьте. – vivekpansara

+0

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

ответ

2

Вы должны генерировать все комбинации month с и year с первым. А потом сделать LEFT JOIN на rm_report:

WITH CteTally(N) AS(
    SELECT N FROM(VALUES 
     (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12) 
    )t(N) 
), 
CteDates(YearPart, MonthPart, YearName, MonthName) AS(
    SELECT 
     DATEPART(YEAR, DATEADD(MONTH, t.N - 1, DATEADD(YEAR, a.Y - 1900, 0))), 
     DATEPART(MONTH, DATEADD(MONTH, t.N - 1, DATEADD(YEAR, a.Y - 1900, 0))), 
     DATENAME(YEAR, DATEADD(MONTH, t.N - 1, DATEADD(YEAR, a.Y - 1900, 0))), 
     DATENAME(MONTH, DATEADD(MONTH, t.N - 1, DATEADD(YEAR, a.Y - 1900, 0))) 
    FROM(
     SELECT DISTINCT DATEPART(YEAR, call_date) AS Y 
     FROM rm_report 
    )a 
    CROSS JOIN CteTally t 
) 
SELECT 
    COUNT(r.call_date) AS Events, 
    d.YearPart, 
    d.MonthPart, 
    d.YearName, 
    d.MonthName 
FROM CteDates d 
LEFT JOIN rm_report r 
    ON d.YearPart = DATEPART(YEAR, r.call_date) 
    AND d.YearName= DATENAME(YEAR, r.call_date) 
    AND d.MonthPart = DATEPART(MONTH, r.call_date) 
    AND d.MonthName = DATENAME(MONTH, r.call_date) 
GROUP BY 
    d.YearPart, d.YearName, d.MonthPart, d.MonthName 
ORDER BY 
    d.YearName, d.MonthPart 
+0

Хорошо - это действительно полезно - я попробую и дам вам знать – skyman

+0

Хорошо, сделал обновление на 'COUNT'. Если бы вы могли просто предоставить образцы данных, я мог бы проверить их для вас. –

+0

mmm - Я получаю cteDates.MonthPart недействителен, потому что он не содержится в функции агрегации или предложения GroupBY? – skyman

2

Создайте временную таблицу/CTE с одним столбцом MONTHPART, который содержит числа от 1 до 12. Правильно Присоедините свой результат к этой таблице и замените NULLS на ноль.

Пример:

CREATE TABLE #temp 
    ( 
    [monthpart] INT 
) 

INSERT INTO #Temp (MONTHPART) Values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12) 

--SELECT * FROM #Temp 
SELECT [monthpart], 
     ISNULL([deptid], 0)  AS Department, 
     ISNULL(SUM([salart]), 0) AS Salary 
FROM [DeeTest].[dbo].[employeesalary] 
     RIGHT JOIN #temp 
       ON empid = monthpart 
GROUP BY deptid, 
      monthpart 

DROP TABLE #temp 
+0

Не совсем уверен, как, но позвольте мне попытаться вернуться к вам. – skyman

+0

Отредактировано, добавлен пример .. Приветствия! –

2

Вы можете создать таблицу календарь как предложил Aaron Bertrand и написать запрос как:

--create Calendar table based on the max and min dates in table 
DECLARE @Mincall_date DATETIME,@FromDate DATETIME, @ToDate DATETIME; 
SET @Mincall_date = (SELECT MIN (Call_date) FROM @rm_report); 
SET @FromDate= DATEADD(yy, DATEDIFF(yy,0,@Mincall_date), 0) 
SET @ToDate = (SELECT MAX (Call_date) FROM @rm_report); 


-- just the months in that period 
DECLARE @Calendar TABLE(TheDate DATETIME,TheMonth INT, TheYear INT) 

INSERT INTO @Calendar  
SELECT TOP (DATEDIFF(MONTH, @FromDate, @ToDate)+1) 
    TheDate = DATEADD(MONTH, number, @FromDate), 
    TheMonth = MONTH(DATEADD(MONTH, number, @FromDate)), 
    TheYear = YEAR(DATEADD(MONTH, number, @FromDate)) 
    FROM [master].dbo.spt_values 
    WHERE [type] = N'P' ORDER BY number; 


--SELECT * FROM @Calendar 

SELECT ISNULL(T.[Events],0) AS [Events], 
     ISNULL(T.YearPart,C.TheYear) AS YearPart, 
     ISNULL(T.MonthPart,C.TheMonth) AS MonthPart, 
     ISNULL(T.YearName,DATENAME(YYYY,C.TheDate)) AS YearName, 
     ISNULL(T.MonthName,DATENAME(MM,C.TheDate)) AS MonthName 
FROM @Calendar C 
LEFT JOIN 
(  
SELECT COUNT(*) AS Events, 
     datepart(YYYY, call_date) AS YearPart, 
     datepart(MM, call_date) As MonthPart, 
     datename(YYYY, call_date) AS YearName, 
     dateName(MM, call_date) As MonthName 
FROM @rm_report 
GROUP BY 
    datename(year, call_date), 
    datename(month, call_date), 
    datepart(year, call_date), 
    datepart(month, call_date) 
    ) T 
    ON C.TheMonth=T.MonthPart AND C.TheYear = T.YearPart 
ORDER BY 
    YearPart, 
    MonthPart; 
0

Это может быть сделано в простой выберите

DECLARE @rm_report table 
(
    call_date datetime 
) 

INSERT @rm_report VALUES (GETDATE()) 

SELECT 
    (
     SELECT COUNT(*) 
     FROM @rm_report 
     WHERE YEAR(call_date) = year.Value AND MONTH(call_date) = month.Value 
    ) AS Events, 
    year.Value AS YearPart, 
    month.Value AS MonthPart, 
    year.Value AS YearName, 
    DATENAME(MM, DATEADD(MONTH, month.Value, '2000-12-01')) AS MonthName 
FROM 
    (VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)) month(Value) 
    CROSS JOIN 
    (
     SELECT DISTINCT YEAR(call_date) Value FROM @rm_report 
    ) year 
+0

Я тоже попробую это сделать - спасибо – skyman