如何使用 SQL Server 在此查询中按天对结果进行分组?

Posted

技术标签:

【中文标题】如何使用 SQL Server 在此查询中按天对结果进行分组?【英文标题】:How I can group the results by day in this query with SQL Server? 【发布时间】:2016-08-11 08:35:48 【问题描述】:

sql fiddle demo here

我有这个日记表的表结构:

 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);

DiaryTimetable 表的结构如下:

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');

我使用此查询来获取用户 ID 1409 的最大小时和最小小时,以获取每天输入的时间和离开工作的时间。 idday 对应于星期几。例如 1 是星期一,2 是星期二等等...

 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

这个查询给出这个结果:

我想得到这个结果:

    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

我有一个列 (IsAnExtraHour) 此列指示该行是否在一天中有额外的时间,例如一个员工在星期一 09:00 到 11:00 开始工作,然后在下午 15:00 再次工作到17:00,所以我想知道如何将这个时间分组在同一行,希望我已经能够表达清楚,我接受建议谢谢。

【问题讨论】:

应该这样问 SQL 问题。一切都像 Esraa_92 一样! 感谢您的评论;-D 不要对列别名使用单引号。为避免混淆和难以发现的错误,您应该只对字符串和日期/时间常量使用单引号。 【参考方案1】:
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

【讨论】:

感谢您的回答,这很容易理解:-D【参考方案2】:

我使用来自@Quassnoi 的代码并添加了这个:

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

我希望这对某人有所帮助,谢谢大家的回答。

【讨论】:

【参考方案3】:

我解决这个问题的方法是分别计算你的标准时间和加班时间,就像这样;

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

【讨论】:

当然,您可以在 IdDay 上做一个 case 语句,或者如果您有一个将日期作为文本返回的日期表(例如星期一而不是 1),则可以将其链接到日期表【参考方案4】:

您可以先获得非加班时间,然后通过 UserId 和 IdDay 将加班时间留给他们。像这样:

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

【讨论】:

以上是关于如何使用 SQL Server 在此查询中按天对结果进行分组?的主要内容,如果未能解决你的问题,请参考以下文章

在 django admin 中按天分组?

如何在 PL/SQL 中按每天分组?

按天分组的 SQL 查询

iPhone CoreData:如何按天对获取的结果进行分组?

当一组相关的 Oracle 表没有时间信息时,按天对它们进行分区

如何在bigquery中按天计算(非)连续记录?