2016-04-19 12 views
9

sql fiddle demo hereJak mogę grupować wyniki według dnia w zapytaniu z SQL Server?

mam tej struktury tabeli dla tabeli Dziennik:

CREATE TABLE Diary 
(
    [IdDiary] bigint, 
    [UserId] int, 
    [IdDay] numeric(18,0), 
    [IsAnExtraHour] bit 
); 

INSERT INTO Diary ([IdDiary], [UserId], [IdDay], [IsAnExtraHour]) 
values 
(51, 1409, 1, 0), 
(52, 1409, 1, 1), 
(53, 1409, 3, 0), 
(54, 1409, 5, 0), 
(55, 1409, 5, 1), 
(56, 1408, 2, 0); 

i to strukturę DiaryTimetable tabeli:

CREATE TABLE DiaryTimetable 
(
    [IdDiary] bigint, 
    [Hour] varchar(50) 
); 

    INSERT INTO DiaryTimetable ([IdDiary], [Hour]) 
VALUES 
    (51, '09:00'), 
    (51, '09:30'), 
    (51, '10:00'), 
    (51, '10:30'), 
    (51, '11:00'), 
    (52, '15:00'), 
    (52, '15:30'), 
    (52, '16:00'), 
    (52, '16:30'), 
    (52, '17:00'), 
    (53, '11:00'), 
    (53, '11:30'), 
    (53, '12:00'), 
    (53, '12:30'), 
    (53, '13:00'), 
    (54, '10:00'), 
    (54, '10:30'), 
    (54, '11:00'), 
    (54, '11:30'), 
    (54, '12:00'), 
    (55, '16:00'), 
    (55, '16:30'), 
    (55, '17:00'), 
    (55, '17:30'), 
    (55, '18:00'), 
    (56, '15:00'), 
    (56, '15:30'), 
    (56, '16:00'), 
    (56, '16:30'), 
    (56, '17:00'); 

użyłem tej kwerendy, aby uzyskać max godzinę i min godzinę dla użytkownika 1409, aby uzyskać dla każdego dnia czas, który wchodzi i czas, który opuści pracę. Idday odpowiada liczbie dni tygodnia. Na przykład 1 jest poniedziałek, 2 wtorek itd ...

SELECT d.IdDiary, d.IdDay, MIN(Hour) as 'Start Time', MAX(Hour) as 'End Time', IsAnExtraHour 
FROM Diary AS d 
LEFT JOIN DiaryTimetable AS dt ON d.IdDiary = dt.IdDiary 
where userid = 1409 
GROUP BY d.IdDiary, d.IdDay, IsAnExtraHour 

Ta kwerenda dać ten wynik:

enter image description here

chcę uzyskać ten wynik:

Day  Start Time End Time Start Extra Time End Extra Time 
    -----  ---------- -------- ---------------  --------------- 
    Monday  09:00   11:00  15:00    17:00 
    Wednessday 11:00   13:00   
    Friday  10:00   12:00  16:00    18:00 

I kolumna (IsAnExtraHour) ta kolumna wskazuje, czy ten wiersz ma dodatkowe godziny w ciągu dnia, na przykład praca rozpoczynająca pracę w poniedziałek od 09:00 do 11:00, a następnie działa ponownie po południu o 15: 00 do 17:00, więc chcę wiedzieć, jak pogrupować te godziny w tym samym rzędzie, mam nadzieję, że udało mi się jasno wyrazić, akceptuję sugestie dzięki.

+10

Tak należy zadawać pytania SQL. Wszyscy robią tak, jak Esraa_92! – Quassnoi

+2

Dziękujemy za komentarz ;-D –

+0

Nie używaj pojedynczych cudzysłowów dla aliasów kolumn. Aby uniknąć pomyłek i trudnych do znalezienia błędów, powinieneś używać pojedynczych cudzysłowów tylko dla ciągów i stałych daty/czasu. –

Odpowiedz

9
SELECT d.IdDay, 
     MIN(CASE WHEN isAnExtraHour = 0 THEN hour END) as 'Start Time', 
     MAX(CASE WHEN isAnExtraHour = 0 THEN hour END) as 'End Time', 
     MIN(CASE WHEN isAnExtraHour = 1 THEN hour END) as 'Start Extra Time', 
     MAX(CASE WHEN isAnExtraHour = 1 THEN hour END) as 'End Extra Time' 
FROM Diary AS d 
LEFT JOIN 
     DiaryTimetable AS dt 
ON  dt.IdDiary = d.IdDiary 
WHERE userid = 1409 
GROUP BY 
     d.IdDay 
+0

Dzięki za odpowiedź łatwo to zrozumieć: -RE –

1

Sposób, w jaki podchodzę do tego, to wypracowanie osobno standardowych i dodatkowych godzin, coś w tym stylu;

SELECT d.IdDay 
    ,MIN(dt.StartTime) AS 'Start Time' 
    ,MAX(dt.EndTime) AS 'End Time' 
    ,MIN(ex.StartTime) AS 'Start Extra Time' 
    ,MAX(ex.EndTime) AS 'End Extra Time' 
FROM Diary AS d 
LEFT JOIN (
    SELECT IdDiary 
     ,MIN(Hour) AS StartTime 
     ,MAX(Hour) AS EndTime 
    FROM DiaryTimetable 
    GROUP BY IdDiary 
    ) AS dt ON d.IdDiary = dt.IdDiary 
    AND d.IsAnExtraHour = 0 
LEFT JOIN (
    SELECT IdDiary 
     ,MIN(Hour) AS StartTime 
     ,MAX(Hour) AS EndTime 
    FROM DiaryTimetable 
    GROUP BY IdDiary 
    ) AS ex ON d.IdDiary = ex.IdDiary 
    AND d.IsAnExtraHour = 1 
WHERE userid = 1409 
GROUP BY d.IdDay 
+0

Oczywiście, możesz zrobić oświadczenie o sprawie na IdDay lub połączyć je z tabelą dat, jeśli masz, aby zwrócić dzień jako tekst (np. Poniedziałek zamiast 1) –

1

Najpierw możesz uzyskać dodatkowe godziny i pozostawić im dodatkowe godziny za pomocą identyfikatora użytkownika i idDay. Tak:

SELECT 
    CASE BaseHours.IdDay 
     WHEN 1 THEN 'Monday' 
     WHEN 2 THEN 'Tuesday' 
     WHEN 3 THEN 'Wednesday' 
     WHEN 4 THEN 'Thursday' 
     WHEN 5 THEN 'Friday' 
     WHEN 6 THEN 'Saturday' 
     WHEN 7 THEN 'Sunday' 
    END AS [WeekDay], 
    MIN(BaseTimeTable.Hour) as 'Start Time', 
    MAX(BaseTimeTable.Hour) as 'End Time', 
    MIN(ExtraTimeTable.Hour) as 'Start Extra Time', 
    MAX(ExtraTimeTable.Hour) as 'End Extra Time' 
FROM Diary AS BaseHours 
LEFT JOIN Diary ExtraHours 
    ON ExtraHours.UserId = BaseHours.UserId 
     AND ExtraHours.IdDay = BaseHours.IdDay AND ExtraHours.IsAnExtraHour = 1 
JOIN DiaryTimetable AS BaseTimeTable 
    ON BaseHours.IdDiary = BaseTimeTable.IdDiary 
LEFT JOIN DiaryTimetable AS ExtraTimeTable 
    ON ExtraHours.IdDiary = ExtraTimeTable.IdDiary 
WHERE BaseHours.Userid = 1409 AND BaseHours.IsAnExtraHour = 0 
GROUP BY BaseHours.IdDay 
5

używam kod z @Quassnoi i dodałem to:

SELECT DATENAME(weekday, d.idday-1) as 'Day' , 
     MIN(CASE WHEN isAnExtraHour = 0 THEN hour END) AS 'Start Time', 
     MAX(CASE WHEN isAnExtraHour = 0 THEN hour END) AS 'End Time', 
     MIN(CASE WHEN isAnExtraHour = 1 THEN hour END) AS 'Start Extra Time', 
     MAX(CASE WHEN isAnExtraHour = 1 THEN hour END) AS 'End Extra Time' 
FROM Diary AS d 
LEFT JOIN DiaryTimetable AS dt ON dt.IdDiary = d.IdDiary 
WHERE userid = 1409 
GROUP BY d.IdDay 

Mam nadzieję, że komuś pomóc, dzięki wszystkim za odpowiedzi.

Powiązane problemy