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

时间:2017-11-06 21:59:40

标签: sql datetime common-table-expression

使用以下数据:

    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之间每天中午找到犁的StatType。您会注意到记录#8615的statStart为9:22 am,statEnd为11:21 am。此记录不应作为结果集的一部分返回。此外,由于statType在记录8406和&之间不会改变。 8625由于省略了8615,我需要提前执行状态以准确计算DATEDIFF(或StatusDays)。

我尝试了很多不同的方法,包括LAG / LEAD和CTE的组合,但是,因为一条记录8615不符合中午标准,它会及时创建一个“GAP”,对我的SSRS图表产生负面影响。 8406在9:21结束,但8625直到11:22才开始。

我希望有人可以帮我创建我的查询部分,这样我就可以在两个日期参数之间的中午获取状态。

谢谢!

更新:使用Sam cd的解决方案,我得到以下结果(如下)。请注意,当加入CTE建议的日期时,结果集省略了记录8615,记录8406的statEnd比记录8625的statStart小1.5小时。这1.5小时的差距是记录8615通常的位置。这个差距在我的SSRS条形图中引起了一个问题,因为我需要操作的状态流过差距,并且StatusDays一直读到'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和840之间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 个答案:

答案 0 :(得分:0)

使用递归CTE创建日期表:

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

public function(MyExampleRequest $request)

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

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

答案 1 :(得分:0)

我认为您正在尝试做类似下面的事情。我使用CTE ...在其中我添加一个索引号(ROW_NUMBER)并按statStart对行进行排序。我在WHERE子句中排除了非中午值。要消除“差距”,您可以选择下一个ROW_NUMBER的startstat。我没有使用原始的终结时间值。

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]