不规则时间帧上的T-SQL分组

时间:2014-02-25 08:17:44

标签: sql-server group-by rollup

我有一个SQL语句,如果每个小时都需要我的SUMmations(SQL Server 2008),它可以很好地工作。 DATEPART(HOUR, DATE_TIME)为我做了所有精彩的工作。

SELECT  SUM(case STATION_ID when 'S-WELDCHK' then 1 else 0 end) as WELDCHK
       ,SUM(case STATION_ID when 'S-GLUING-OUT-OK' then 1 else 0 end) as GLUING
       ,SUM(case STATION_ID when 'S-GLUING-OUT-NOK' then 1 else 0 end) as 'GLUING-NOK'
       ,SUM(case STATION_ID when 'S-ULTRAWELD-OUT-OK' then 1 else 0 end) as ULTRAWELD
       ,SUM(case STATION_ID when 'S-ULTRAWELD-OUT-NOK' then 1 else 0 end) as 'ULTRAWELD-NOK'
       ,SUM(case STATION_ID when 'S-BOLTFAST-OUT-OK' then 1 else 0 end) as BOLTFAST
       ,SUM(case STATION_ID when 'S-BOLTFAST-OUT-NOK' then 1 else 0 end) as 'BOLTFAST-NOK'
       ,SUM(case STATION_ID when 'S-MAPVISION-OUT-OK' then 1 else 0 end) as MAPVISION
       ,SUM(case STATION_ID when 'S-MAPVISION-OUT-NOK' then 1 else 0 end) as 'MAPVISION-NOK'
       ,SUM(case STATION_ID when 'S-CHECKFIX-OUT-OK' then 1 else 0 end) as CHECKFIX
       ,SUM(case STATION_ID when 'S-CHECKFIX-OUT-NOK' then 1 else 0 end) as 'CHECKFIX-NOK'
       ,SUM(case STATION_ID when 'S-EJOT-OUT-OK' then 1 else 0 end) as EJOT
       ,SUM(case STATION_ID when 'S-EJOT-OUT-NOK' then 1 else 0 end) as 'EJOT-NOK'
  FROM [dbFactory].[dbo].[Events]
  where (DATEPART(yy,DATE_TIME) = 2014
         AND DATEPART(mm,DATE_TIME) = 2
         AND DATEPART(dd,DATE_TIME)= 5)
  GROUP BY 
        DATEPART(HOUR, DATE_TIME)
 with rollup

我真正想要的是我在临时表中有不规则时间段的SUMS(为简洁而截断)

Start         Finish
06:00:00.000  06:30:00.000
06:30:00.000  07:30:00.000
07:30:00.000  08:30:00.000
08:30:00.000  09:30:00.000
09:30:00.000  10:00:00.000
10:00:00.000  10:30:00.000
10:30:00.000  11:30:00.000
11:30:00.000  12:30:00.000
12:30:00.000  13:30:00.000
13:30:00.000  14:00:00.000

网站上的任何建议或我应该阅读的内容以解决此问题。应该有一个工具来汇总用户定义的函数,也许我可以通过START和FINISH期间以及事务的DATE_TIME

2 个答案:

答案 0 :(得分:1)

使用between

将您的查询加入期间表
     inner join Periods on events.DATE_TIME between Periods.Start and Periods.End

并按期间表中的字段分组

     group by Periods.Start

NB。如果时间段恰好在两个时期之间的边界上,您需要决定会发生什么。您可能需要调整期间,或使用>加入和< =

您可能还想查看PIVOT而不是使用SUM(CASE...构造。

答案 1 :(得分:0)

这就是我获得工作解决方案的方式。它不漂亮或高效。这是目前每24小时运行一次的报告的一部分。

获取数据的存储过程

USE [dbFactory]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Create date: 20140225
-- Description: Used by a report to extract SUM values for various Factory stations
-- =============================================
ALTER PROCEDURE [dbo].[spRptFetchStationActivitySummationsWithGroupBy] 
    @Day DATETIME
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @START DATETIME;
    DECLARE @FINISH DATETIME;

    if @Day IS NULL
    BEGIN
        SET @DAY = GETDATE();
    END
    -- Subtract a day from the day passed in and set its time to 6am 
    DECLARE @ActualDay DATETIME = DATEADD(day,-1,DATEADD(HOUR,6,DATEADD(dd, 0, DATEDIFF(dd, 0, @DAY))));
    DECLARE @dtTwentyFoursHoursLater DATETIME = DATEADD(HOUR,24,@ActualDay);

    -- If a transaction time is exactly on 6:00 am we want to avoid counting it twice.
    -- There are granularity issues on milliseconds
    SET @dtTwentyFoursHoursLater = DATEADD(millisecond,-2,@dtTwentyFoursHoursLater);
    -- SELECT @ActualDay,@dtTwentyFoursHoursLater

    CREATE TABLE #LocalEvents(
        [SERIAL_NUMBER] [nchar](20) NOT NULL,
        [DATE_TIME] [datetime] NOT NULL,
        [STATION_ID] [nchar](20) NOT NULL,
        [SUCCESS] [char](1) NOT NULL,
        [OVERRIDDEN] [char](1) NOT NULL,
        [USER_NAME] [nchar](30) NOT NULL,
        [EVENT_ID] [smallint] NOT NULL,
        [EXTRA_INFO] [nchar](30) NOT NULL);

    -- Stuff in the dummy entries which have one entry for each time frame from for the GROUP BY
    INSERT INTO #LocalEvents([SERIAL_NUMBER],
                             [DATE_TIME],
                             [STATION_ID],
                             [SUCCESS],
                             [OVERRIDDEN],
                             [USER_NAME],
                             [EVENT_ID],
                             [EXTRA_INFO]
                           )    
        SELECT               [SERIAL_NUMBER],
                             [DATE_TIME],
                             [STATION_ID],
                             [SUCCESS],
                             [OVERRIDDEN],
                             [USER_NAME],
                             [EVENT_ID],
                             [EXTRA_INFO]

        FROM dbCCB.dbo.Events;                         

    -- Stuff in the real events of the past 24 hours
    INSERT INTO #LocalEvents([SERIAL_NUMBER],
                             [DATE_TIME],
                             [STATION_ID],
                             [SUCCESS],
                             [OVERRIDDEN],
                             [USER_NAME],
                             [EVENT_ID],
                             [EXTRA_INFO]
                           )    
        SELECT [SERIAL_NUMBER],
                             [DATE_TIME],
                             [STATION_ID],
                             [SUCCESS],
                             [OVERRIDDEN],
                             [USER_NAME],
                             [EVENT_ID],
                             [EXTRA_INFO]

        FROM dbFactory.dbo.Events
        WHERE DATE_TIME BETWEEN @ActualDay AND @dtTwentyFoursHoursLater;


    -- The UDF returns the first two chars to show the order as is 01 to 30 for the time periods.
    -- We chop them off (SUBSTRING) to provide the client with the start and end times of the time period.
    SELECT  SUBSTRING(dbo.fnReturnGroupWhenBetweenTimes( CONVERT(TIME,DATE_TIME)),4,200) as [Time] 
           ,SUM(case STATION_ID when 'S-WELDCHK' then 1 else 0 end) as WELDCHK
           ,SUM(case STATION_ID when 'S-GLUING-OUT-OK' then 1 else 0 end) as GLUING
           ,SUM(case STATION_ID when 'S-GLUING-OUT-NOK' then 1 else 0 end) as 'GLUING-NOK'
           ,SUM(case STATION_ID when 'S-ULTRAWELD-OUT-OK' then 1 else 0 end) as ULTRAWELD
           ,SUM(case STATION_ID when 'S-ULTRAWELD-OUT-NOK' then 1 else 0 end) as 'ULTRAWELD-NOK'
           ,SUM(case STATION_ID when 'S-BOLTFAST-OUT-OK' then 1 else 0 end) as BOLTFAST
           ,SUM(case STATION_ID when 'S-BOLTFAST-OUT-NOK' then 1 else 0 end) as 'BOLTFAST-NOK'
           ,SUM(case STATION_ID when 'S-MAPVISION-OUT-OK' then 1 else 0 end) as MAPVISION
           ,SUM(case STATION_ID when 'S-MAPVISION-OUT-NOK' then 1 else 0 end) as 'MAPVISION-NOK'
           ,SUM(case STATION_ID when 'S-CHECKFIX-OUT-OK' then 1 else 0 end) as CHECKFIX
           ,SUM(case STATION_ID when 'S-CHECKFIX-OUT-NOK' then 1 else 0 end) as 'CHECKFIX-NOK'
           ,SUM(case STATION_ID when 'S-EJOT-OUT-OK' then 1 else 0 end) as EJOT
           ,SUM(case STATION_ID when 'S-EJOT-OUT-NOK' then 1 else 0 end) as 'EJOT-NOK'
           /*,SUM(case STATION_ID when 'S-GENERIC' then 1 else 0 end) as 'GENERIC'*/
      FROM #LocalEvents
      GROUP BY dbo.fnReturnGroupWhenBetweenTimes(CONVERT(TIME,DATE_TIME))
      WITH ROLLUP

      DROP TABLE #LocalEvents;
END

将事件过滤为不规则变化的UDF。

USE [dbFactory]
GO
/****** Object:  UserDefinedFunction [dbo].[fnReturnGroupWhenBetweenTimes]    Script Date: 03/14/2014 12:44:54 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Create date: 20140226
-- Description: Returns a 1 if Date's TIME is between two dates
-- =============================================
ALTER FUNCTION [dbo].[fnReturnGroupWhenBetweenTimes] 
(
    -- Add the parameters for the function here
    @TestTime TIME
)
RETURNS VARCHAR(20)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @Result VARCHAR(20)

    -- Add the T-SQL statements to compute the return value here
    SELECT @Result = 
        case
            when @TestTime between CONVERT(TIME,'06:00',14) and CONVERT(TIME,'06:30',14) then '01 06:00 06:30'
            when @TestTime between CONVERT(TIME,'06:30',14) and CONVERT(TIME,'07:30',14) then '02 06:30 07:30'
            when @TestTime between CONVERT(TIME,'07:30',14) and CONVERT(TIME,'08:30',14) then '03 07:30 08:30'
            when @TestTime between CONVERT(TIME,'08:30',14) and CONVERT(TIME,'09:30',14) then '04 08:30 09:30'
            when @TestTime between CONVERT(TIME,'09:30',14) and CONVERT(TIME,'10:00',14) then '05 09:30 10:00'
            when @TestTime between CONVERT(TIME,'10:00',14) and CONVERT(TIME,'10:30',14) then '06 10:00 10:30'
            when @TestTime between CONVERT(TIME,'10:30',14) and CONVERT(TIME,'11:30',14) then '07 10:30 11:30'
            when @TestTime between CONVERT(TIME,'11:30',14) and CONVERT(TIME,'12:30',14) then '08 11:30 12:30' 
            when @TestTime between CONVERT(TIME,'12:30',14) and CONVERT(TIME,'13:30',14) then '09 12:30 13:30' 
            when @TestTime between CONVERT(TIME,'13:30',14) and CONVERT(TIME,'14:00',14) then '10 13:30 14:00'

            when @TestTime between CONVERT(TIME,'14:00',14) and CONVERT(TIME,'14:30',14) then '11 14:00 14:30'
            when @TestTime between CONVERT(TIME,'14:30',14) and CONVERT(TIME,'15:30',14) then '12 14:30 15:30'
            when @TestTime between CONVERT(TIME,'15:30',14) and CONVERT(TIME,'16:30',14) then '13 15:30 16:30'
            when @TestTime between CONVERT(TIME,'16:30',14) and CONVERT(TIME,'17:30',14) then '14 16:30 17:30'
            when @TestTime between CONVERT(TIME,'17:30',14) and CONVERT(TIME,'18:00',14) then '15 17:30 18:00'
            when @TestTime between CONVERT(TIME,'18:00',14) and CONVERT(TIME,'18:30',14) then '16 18:00 18:30'
            when @TestTime between CONVERT(TIME,'18:30',14) and CONVERT(TIME,'19:30',14) then '17 18:30 19:30'
            when @TestTime between CONVERT(TIME,'19:30',14) and CONVERT(TIME,'20:30',14) then '18 19:30 20:30'
            when @TestTime between CONVERT(TIME,'20:30',14) and CONVERT(TIME,'21:30',14) then '19 20:30 21:30'
            when @TestTime between CONVERT(TIME,'21:30',14) and CONVERT(TIME,'22:00',14) then '20 21:30 22:00'

            when @TestTime between CONVERT(TIME,'22:00',14) and CONVERT(TIME,'22:30',14) then '21 22:00 22:30'
            when @TestTime between CONVERT(TIME,'22:30',14) and CONVERT(TIME,'23:30',14) then '22 22:30 23:30'

            when @TestTime between CONVERT(TIME,'23:30',14) and CONVERT(TIME,'23:59:59.998',14) then '23 23:30 00:30'
            when @TestTime between CONVERT(TIME,'00:00',14) and CONVERT(TIME,'00:30',14) then '23 23:30 00:30'

            when @TestTime between CONVERT(TIME,'00:30',14) and CONVERT(TIME,'01:30',14) then '24 00:30 01:30'
            when @TestTime between CONVERT(TIME,'01:30',14) and CONVERT(TIME,'02:00',14) then '25 01:30 02:00'
            when @TestTime between CONVERT(TIME,'02:00',14) and CONVERT(TIME,'02:30',14) then '26 02:00 02:30' 
            when @TestTime between CONVERT(TIME,'02:30',14) and CONVERT(TIME,'03:30',14) then '27 02:30 03:30'
            when @TestTime between CONVERT(TIME,'03:30',14) and CONVERT(TIME,'04:30',14) then '28 03:30 04:30'
            when @TestTime between CONVERT(TIME,'04:30',14) and CONVERT(TIME,'05:30',14) then '29 04:30 05:30'
            when @TestTime between CONVERT(TIME,'05:30',14) and CONVERT(TIME,'06:00',14) then '30 05:30 06:00'

            else 'UnKnown'
        end

    -- Return the result of the function
    RETURN @Result

END

虚拟事件文件的内容减去几列重复数据

SERIAL_NUMBER           DATE_TIME
DUMMY-SERIAL            2014-03-14 00:00:00.000
DUMMY-SERIAL            2014-03-14 01:00:00.000
DUMMY-SERIAL            2014-03-14 01:45:00.000
DUMMY-SERIAL            2014-03-14 02:15:00.000
DUMMY-SERIAL            2014-03-14 03:00:00.000
DUMMY-SERIAL            2014-03-14 04:00:00.000
DUMMY-SERIAL            2014-03-14 05:00:00.000
DUMMY-SERIAL            2014-03-14 05:45:00.000
DUMMY-SERIAL            2014-03-14 06:15:00.000
DUMMY-SERIAL            2014-03-14 07:00:00.000
DUMMY-SERIAL            2014-03-14 08:00:00.000
DUMMY-SERIAL            2014-03-14 09:00:00.000
DUMMY-SERIAL            2014-03-14 09:45:00.000
DUMMY-SERIAL            2014-03-14 10:15:00.000
DUMMY-SERIAL            2014-03-14 11:00:00.000
DUMMY-SERIAL            2014-03-14 12:00:00.000
DUMMY-SERIAL            2014-03-14 13:00:00.000
DUMMY-SERIAL            2014-03-14 13:45:00.000
DUMMY-SERIAL            2014-03-14 14:15:00.000
DUMMY-SERIAL            2014-03-14 15:00:00.000
DUMMY-SERIAL            2014-03-14 16:00:00.000
DUMMY-SERIAL            2014-03-14 17:00:00.000
DUMMY-SERIAL            2014-03-14 17:45:00.000
DUMMY-SERIAL            2014-03-14 18:15:00.000
DUMMY-SERIAL            2014-03-14 19:00:00.000
DUMMY-SERIAL            2014-03-14 20:00:00.000
DUMMY-SERIAL            2014-03-14 21:00:00.000
DUMMY-SERIAL            2014-03-14 21:45:00.000
DUMMY-SERIAL            2014-03-14 22:15:00.000
DUMMY-SERIAL            2014-03-14 23:00:00.000

感谢StackOverflow上的很多人提供的所有帮助。我读了很多问题和答案。 我现在必须在我的小组中了解FIRST_VALUE和LAST_VALUE,但要在2008年而不是2012年开始工作。它永远不会结束。