代码之家  ›  专栏  ›  技术社区  ›  JustPeachy

SQL使用DateRange和DATETIME列查找每天中午处于范围内的状态

  •  0
  • JustPeachy  · 技术社区  · 8 年前

    使用以下数据:

        Item    Record  StatType      statStart                 statEnd
        Plow    8860    Operational   2017-08-29 16:59:48.907   2017-11-06 15:35:15.290
        Plow    8859    Inspection    2017-08-29 16:56:59.460   2017-08-29 16:58:48.907
        Plow    8830    Operational   2017-08-23 18:38:45.530   2017-08-29 16:55:59.460
        Plow    8730    Inspection    2017-07-31 15:34:10.387   2017-08-23 18:37:45.530
        Plow    8625    Operational   2017-07-17 11:22:00.000   2017-07-31 15:33:10.387
        Plow    8615    Inspection    2017-07-17 09:22:58.127   2017-07-17 11:21:00.000
        Plow    8406    Operational   2017-06-05 14:42:32.837   2017-07-17 09:21:58.127
        Plow    8399    Inspection    2017-06-02 17:02:55.107   2017-06-05 14:41:32.837
        Plow    8332    Operational   2017-05-23 09:30:37.707   2017-06-02 17:01:55.107
    

    我需要在每天中午@startDate和@endDate之间找到犁的状态类型。您会注意到,记录#8615的statStart为上午9:22,statEnd为上午11:21。此记录不应作为结果集的一部分返回。此外,由于statType不会在记录8406&8625由于省略了8615,我需要将状态向前推进,以准确地计算DATEDIFF(或StatusDays)。

    我尝试了许多不同的方法,包括滞后/超前和连续时序误差的组合,但是,由于一个记录8615不符合中午标准,它在时间上产生了一个“差距”,对我的SSRS图产生了负面影响。请注意,8406在9:21结束,但8625直到11:22才开始。

    我希望有人能够帮助我创建查询的一部分,使我能够在两个日期参数之间获得每天中午的状态。

    非常感谢。

    更新:使用Sam cd的解决方案,我得到以下结果(如下)。注意,当加入到CTE建议的日期时,结果集忽略了记录8615,记录8406的statEnd比记录8625的statStart少1.5小时。这1.5小时的差距是8615的正常记录。这个间隙在我的SSR条形图中引起了一个问题,因为我需要操作状态通过间隙,还需要状态天数来读取“56”(42+14),直到记录8730。

    更新的结果集:

       Item Record  statusDate              statType    statStart               statEnd                 StatusDays
       Plow 8406    2017-07-15 12:00:00.000 Operational 2017-06-05 14:42:32.837 2017-07-17 09:21:58.127 42
       Plow 8406    2017-07-16 12:00:00.000 Operational 2017-06-05 14:42:32.837 2017-07-17 09:21:58.127 42
       Plow 8625    2017-07-17 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-18 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-19 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-20 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-21 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-22 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-23 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-24 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-25 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-26 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-27 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-28 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-29 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-30 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8625    2017-07-31 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
       Plow 8730    2017-08-01 12:00:00.000 Inspection  2017-07-31 15:34:10.387 2017-08-23 18:37:45.530 23
       Plow 8730    2017-08-02 12:00:00.000 Inspection  2017-07-31 15:34:10.387 2017-08-23 18:37:45.530 23
    

    更新2 :我的查询(我不知道这是否有帮助….)

    DECLARE @StartDate datetime = '07/15/2017'
    DECLARE @EndDate datetime = '07/31/2017'
    DECLARE @item varchar (10) = 'Plow'
    
    ;WITH CTE_Data AS
        (
        SELECT        
     item 
    ,record 
    ,statType 
    ,statStart 
    
    ,CASE WHEN DATEADD(minute, - 1, LEAD(t1.statStart) OVER (PARTITION BY t1.item ORDER BY t1.statStart)) IS NULL THEN GETDATE()
    ELSE DATEADD(minute, - 1, LEAD(t1.statStart) OVER (PARTITION BY t1.item ORDER BY t1.statStart)) END  as statEnd
    
    FROM table1 t1 
    INNER JOIN table2 t2 ON t1.record = t2.record
    
    AND t1.active = 'Y'
    AND t1.item = @item
    ),
    
    cte_Dates AS 
    (
    select dateadd(hour,12,@startDate)  AS StatusDate
    union ALL
    select dateadd(day,1,StatusDate)
    from cte_Dates
    where StatusDate < dateadd(day,1,@endDate)
    ) ,
    
    CTE_Sample as
    (
    SELECT 
    cted.statusdate
    ,Item
    ,Record
    ,StatType 
    ,statStart
    ,statEnd
    
    ,CASE
    WHEN DATEDIFF(day, statStart, statEnd) IS NULL 
        THEN DATEDIFF(day, statStart, GETDATE()) 
    WHEN DATEDIFF(day, statStart, statEnd) = 0
        THEN 1 ELSE DATEDIFF(day, statStart, statEnd)
    END as StatusDays
    
    FROM CTE_Data
    LEFT OUTER JOIN cte_Dates cted ON cted.statusDate >= statStart AND    cted.statusDate <= statEnd
    WHERE cted.statusdate between @StartDate and @EndDate 
    )
    
    SELECT Item, Record, statusDate, statType,  statStart, statEnd,  StatusDays     FROM CTE_Sample 
    WHERE statusdate between @StartDate and @EndDate
    

    如您所见,我正在使用LEAD函数“创建”statEnd,当我将其加入到CTE_Dates时,会添加StatusDate列,并为日期范围内的每一天创建一条记录-但8406和;8625

        Item    Record  statusDate              statType    statStart               statEnd                 StatusDays
        Plow    8406    2017-07-15 12:00:00.000 Operational 2017-06-05 14:42:32.837 2017-07-17 09:21:58.127 42
        Plow    8406    2017-07-16 12:00:00.000 Operational 2017-06-05 14:42:32.837 2017-07-17 09:21:58.127 42
        Plow    8625    2017-07-17 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-18 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-19 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-20 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-21 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-22 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-23 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-24 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-25 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-26 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-27 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-28 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-29 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
        Plow    8625    2017-07-30 12:00:00.000 Operational 2017-07-17 11:22:00.000 2017-07-31 15:33:10.387 14
    
    2 回复  |  直到 8 年前
        1
  •  0
  •   Sam Cohen-Devries    8 年前

    使用递归CTE创建日期表:

    声明@startDate datetime='2017-11-01' ,@enddate datetime='2017-11-30'

    ;with dts as (
    select dateadd(hour,12,@startDate) noon
    union ALL
    select dateadd(day,1,noon)
    from dts
    where noon < dateadd(day,1,@endDate)
    )
    

    然后加入您的表以获取状态

    select
    d.noon
    ,st.StatType
    from statusTable st
     inner join dts d
      on d.noon between st.statStart and st.statEnd
    
        2
  •  0
  •   Zorkolot    8 年前

    我想你是想做下面这样的事情。我使用CTE。。。我在其中添加了一个索引号(ROW_number),并按statStart对行进行排序。我在WHERE子句中排除了非正午值。为了消除“间隙”,您可以选择下一行的startstat。我不使用原始的endtime值。

    DECLARE @temp TABLE (Item varchar(100), Record int, StatType varchar(100), statStart datetime, statEnd datetime)
    INSERT INTO @temp VALUES
     ('Plow', 8860, 'Operational', '2017-08-29 16:59:48.907', '2017-11-06 15:35:15.290')
    ,('Plow', 8859, 'Inspection', '2017-08-29 16:56:59.460', '2017-08-29 16:58:48.907')
    ,('Plow', 8830, 'Operational', '2017-08-23 18:38:45.530', '2017-08-29 16:55:59.460')
    ,('Plow', 8730, 'Inspection', '2017-07-31 15:34:10.387', '2017-08-23 18:37:45.530')
    ,('Plow', 8625, 'Operational', '2017-07-17 11:22:00.000', '2017-07-31 15:33:10.387')
    ,('Plow', 8615, 'Inspection', '2017-07-17 09:22:58.127', '2017-07-17 11:21:00.000')
    ,('Plow', 8406, 'Operational', '2017-06-05 14:42:32.837', '2017-07-17 09:21:58.127')
    ,('Plow', 8399, 'Inspection', '2017-06-02 17:02:55.107', '2017-06-05 14:41:32.837')
    ,('Plow', 8332, 'Operational', '2017-05-23 09:30:37.707', '2017-06-02 17:01:55.107')
    
    DECLARE @startDate datetime = '2017-07-15 12:00:00'
           ,@endDate datetime   = '2017-08-03 12:00:00';
    
    WITH cte AS
    (
    SELECT ROW_NUMBER() OVER(ORDER BY statStart) [idval]
           ,T.*
      FROM @temp T --your tablename
     WHERE (CAST(statStart as time) < '12:00:00' AND CAST(statEnd as time) > '12:00:00'
            OR
            DATEDIFF(HOUR, statStart, statEnd) >= 24
           )
    )
    ,
    cte2 AS
    (
    SELECT @startDate as dateval
    UNION ALL 
    SELECT DATEADD(DAY, 1, dateval)
      FROM cte2
     WHERE dateval < @endDate
    )
    
    SELECT C2.dateval, dT.Item, dT.Record, dT.StatType, dT.statStart, dT.StatEnd
          ,DATEDIFF(DAY, statStart, StatEnd) [StatusDays]
      FROM (
            SELECT C.idval, C.Item, C.Record, C.StatType, C.statStart --, C.statEnd --this has the 'gap'
                  ,COALESCE((SELECT MAX(C2.statStart) FROM cte C2 WHERE C2.idval > C.idval AND C2.StatType = C.StatType), C.statEnd) AS [StatEnd]
              FROM cte C
           ) AS dT
                   INNER JOIN cte2 C2 ON C2.dateval between dT.statStart AND dT.[StatEnd]