2015-08-26 15 views
5

Obecnie mam trudności z uzyskaniem prawidłowych wartości z mojego stołu. Oto mój stółGrupowanie kolumn SQL z jednej tabeli

UWAGA: Kolumna Status ma 3 możliwe wartości (oczyszczone, nieczyste zamknięty)

+-----------+-------------+--------+------------+ 
    |ApplicantID|ApplicantName| Status | HireDate | 
    +-----------+-------------+--------+------------+ 
    |  1  | John Smith |Cleaned |08/26/2015 | 
    |  2  | Alex Murphy |Closed |09/12/2015 | 
    |  3  | Oliver David|Cleaned |01/11/2015 | 
    |  4  | Max Payne |Unclean |03/18/2015 | 
    +-----------+-------------+--------+------------+ 

wyjście Czekam i to powinno być również klasyfikowane przez rok. Na przykład nazywam wszystkie te rekordy na rok 2015, które otrzymuję za pomocą zmiennej @Year.

UWAGA: Kolumna Total jest sumą Cleaned i Unclean

+---------+-----------+-----------+----------+---------+ 
    | Month | Cleaned | Unclean | Closed | Total | 
    +---------+-----------+-----------+----------+---------+ 
    | January|  1  |  0  | 0  | 1 | 
    | February|  0  |  0  | 0  | 0 | 
    | March |  0  |  1  | 0  | 1 | 
    | April |  0  |  0  | 0  | 0 | 
    | May |  0  |  0  | 0  | 0 | 
    | June |  0  |  0  | 0  | 0 | 
    | July |  0  |  0  | 0  | 0 | 
    | August |  1  |  0  | 0  | 1 | 
    |September|  0  |  0  | 1  | 0 | 
    | October|  0  |  0  | 0  | 0 | 
    | November|  0  |  0  | 0  | 0 | 
    | December|  0  |  0  | 0  | 0 | 
    +---------+-----------+-----------+----------+---------+ 

I nie może wydawać się uzyskać odpowiedni kod, dla sql to jest mój aktualny kod.

SELECT Month(HireDate) AS Month, COUNT(*) 
FROM Hires 
GROUP BY Month(HireDate) 

Wiem, że moje kodowanie jest błędne, ponieważ jest niekompletne.

Odpowiedz

3

Generowanie listy numerów od 1 do 12 najpierw do przechowywania wszystkich month s. Następnie wykonaj LEFT JOIN na Hires, aby upewnić się, że wszystkie brakujące miesiące są rozliczane. A następnie za pomocą agregacji warunkowego dla sumy:

SQL Fiddle

;WITH CteMonths AS(
    SELECT * FROM(VALUES 
     (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12) 
    )t(N) 
) 
SELECT 
    Month = DATENAME(MONTH, DATEADD(MONTH, N-1,0)), 
    Cleaned = SUM(CASE WHEN h.Status = 'Cleaned' THEN 1 ELSE 0 END), 
    Closed = SUM(CASE WHEN h.Status = 'Closed' THEN 1 ELSE 0 END), 
    Unclean = SUM(CASE WHEN h.Status = 'Unclean' THEN 1 ELSE 0 END), 
    Total = SUM(CASE WHEN h.Status IN('Cleaned', 'Unclean') THEN 1 ELSE 0 END) 
FROM CteMonths m 
LEFT JOIN Hires h 
    ON m.N = MONTH(h.HireDate) 
    --AND YEAR(h.HireDate) = @year --uncomment this line to filter for year. 
GROUP BY m.N 
ORDER BY m.N 

Jeśli chcesz dołączyć roku:

SQL Fiddle

;WITH CteMonths AS(
    SELECT * FROM(VALUES 
     (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12) 
    )t(N) 
), 
CteYears(yr) AS(
    SELECT DISTINCT YEAR(HireDate) FROM Hires 
), 
CteAllDates(dt) AS(
    SELECT 
     DATEADD(MONTH, m.N - 1, DATEADD(YEAR, y.yr - 1900, 0)) 
    FROM CteMonths m 
    CROSS JOIN CteYears y 
) 
SELECT 
    Year = YEAR(d.dt), 
    Month = DATENAME(MONTH, d.dt), 
    Cleaned = SUM(CASE WHEN h.Status = 'Cleaned' THEN 1 ELSE 0 END), 
    Closed = SUM(CASE WHEN h.Status = 'Closed' THEN 1 ELSE 0 END), 
    Unclean = SUM(CASE WHEN h.Status = 'Unclean' THEN 1 ELSE 0 END), 
    Total = SUM(CASE WHEN h.Status IN('Cleaned', 'Unclean') THEN 1 ELSE 0 END) 
FROM CteAllDates d 
LEFT JOIN Hires h 
    ON MONTH(d.dt) = MONTH(h.HireDate) 
    AND YEAR(d.dt) = YEAR(h.HireDate) 
GROUP BY YEAR(d.dt), MONTH(d.dt), DATENAME(MONTH, d.dt) 
ORDER BY YEAR(d.dt), MONTH(d.dt) 

Jeśli chcesz filtrować za rok , powiedzmy @year = 2015, możesz zastąpić t he poprzednia współczynniki CTE z:

;WITH CteMonths AS(
    SELECT * FROM(VALUES 
     (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12) 
    )t(N) 
), 
CteAllDates(dt) AS(
    SELECT 
     DATEADD(MONTH, m.N - 1, DATEADD(YEAR, @year - 1900, 0)) 
    FROM CteMonths m 
)... 
+0

Tak, z powodu agregatu "SUM". –

+2

Zaczekaj chwilę ... jesteś przemianowany na @wewesthemenace! Nie wiedziałem, że SO pozwala zmienić nazwę użytkownika. –

+0

@TimBiegeleisen Yup, to ja. –

0

Proponuję stworzyć TEMP tabelę z wartościami z 1 do 12 (liczby miesięcy) i JOIN stole z TEMP tabeli. Aby uzyskać wartości jako nazwy kolumn, można użyć wartości PIVOT lub CASE. Można to zrobić w następujący:

INSERT INTO #Months VALUES 
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12) 

SELECT DATENAME(MONTH, DATEADD(MONTH, m.Id-1, 0)) AS [Month] 
     , SUM(CASE WHEN [Status] = 'Cleaned' THEN 1 ELSE 0 END) AS [Cleaned] 
     , SUM(CASE WHEN [Status] = 'Closed' THEN 1 ELSE 0 END) AS [Closed] 
     , SUM(CASE WHEN [Status] = 'Unclean' THEN 1 ELSE 0 END) AS [Unclean] 
     , SUM(CASE WHEN [Status] IN ('Unclean', 'Cleaned') THEN 1 ELSE 0 END) AS [Total] 
FROM #Test t 
RIGHT JOIN #Months m ON m.Id = MONTH(t.HireDate) 
GROUP BY m.Id 

WYJŚCIE

+---------+-----------+-----------+----------+---------+ 
    | Month | Cleaned | Unclean | Closed | Total | 
    +---------+-----------+-----------+----------+---------+ 
    | January |  1  |  0  | 0  | 1 | 
    | February|  0  |  0  | 0  | 0 | 
    | March |  0  |  1  | 0  | 1 | 
    | April |  0  |  0  | 0  | 0 | 
    | May |  0  |  0  | 0  | 0 | 
    | June |  0  |  0  | 0  | 0 | 
    | July |  0  |  0  | 0  | 0 | 
    | August |  1  |  0  | 0  | 1 | 
    |September|  0  |  0  | 1  | 0 | 
    | October |  0  |  0  | 0  | 0 | 
    | November|  0  |  0  | 0  | 0 | 
    | December|  0  |  0  | 0  | 0 | 
    +---------+-----------+-----------+----------+---------+ 

DEMO

można przetestować pod adresem: SQL FIDDLE

Powiązane problemy