计算日期之间可用的周期数并将行值排列为列值

Calculate number of cycles available between dates and arrange row value as column value

我在SQL中有车辆信息数据,顺序如下,

S.No Vehicle_ID status date_on
1 1 Start 2018-05-23
2 1 Start 2021-06-15
3 1 Failed 2020-08-10
4 2 Start 2019-06-23
5 3 Start 2010-04-20
6 3 Failed 2010-05-10
7 4 Start 2011-01-20
8 4 Failed 2015-01-14
9 4 Start 2016-02-25
10 4 Failed 2019-04-10

车辆ID:1

第一个 开始 日期 = 2018-05-23

第一次失败 =2020-08-10

第 2 开始 日期 = 2021-06-15

此处,第 2 个开始 日期没有失败日期,因此我们将今天 日期作为失败日期。

车辆ID:2

第一个 开始 日期 = 2020-08-10

在这里,第一个开始日期没有失败日期,所以我们将今天日期作为失败日期。

基于上述条件,要求结果如下,

Vehicle_ID Start Failed/Running Cycle
1 2018-05-23 2020-08-10 1
1 2021-06-15 Today's date 2
2 2019-06-23 Today's date 1
3 2010-04-20 2010-05-10 1
4 2011-01-20 2015-01-14 1
4 2016-02-25 2019-04-10 2

我尝试使用 PIVOT 函数将行切换到列,但我很难分配周期和日期顺序。

尝试过如下所示的代码,

SELECT * FROM (
  SELECT 
    S_No,
    Vehicle_ID,
    date_on,
    status
    
  FROM vehicle_table where Vehicle_ID is not null  Group by Vehicle_ID,status,S_No,date_on 
) Vehicle_Detail
PIVOT (
  MAX(date_on) 
  FOR status
  IN (
    [Start],
    [Failed]
    
  )
) AS PivotTable where [status] is not null order by [Vehicle_ID]

我会在这里使用 outer apply top 1 结构

create table vehicle_detail (S_No int,  Vehicle_ID int, status varchar(6),  date_on date);

insert vehicle_detail values
(1,   1, 'Start',  '2018-05-23'),
(2,   1, 'Start',  '2021-06-15'),
(3,   1, 'Failed', '2020-08-10'),
(4,   2, 'Start',  '2019-06-23'),
(5,   3, 'Start',  '2010-04-20'),
(6,   3, 'Failed', '2010-05-10'),
(7,   4, 'Start',  '2011-01-20'),
(8,   4, 'Failed', '2015-01-14'),
(9,   4, 'Start',  '2016-02-25'),
(10,  4, 'Failed', '2019-04-10');


select      starts.vehicle_id,
            start             =  starts.date_on,
            [failed/running]  =  isnull(fails.date_on, cast(getdate() as date)),
            cycle             =  row_number() over 
                                 (
                                    partition by starts.vehicle_id 
                                    order by starts.date_on asc
                                 )
from        vehicle_detail  starts
outer apply (
               select    top 1 date_on
               from      vehicle_detail v
               where     v.vehicle_id = starts.vehicle_id
               and       v.status = 'Failed'
               and       v.date_on >= starts.date_on
               order by  date_on asc
            ) fails
where       starts.status = 'Start'
order by    starts.vehicle_id,
            starts.date_on;

另一种方法可能是简单的左连接和子查询:

DECLARE @t TABLE(
  SNo INT
 ,Vehicle_ID int
 ,stat VARCHAR(10)
 ,date_on DATE
)

INSERT INTO @t VALUES
(1     ,1     ,'Start', '2018-05-23')
,(2     ,1     ,'Start', '2021-06-15')
,(3     ,1     ,'Failed', '2020-08-10')
,(4     ,2     ,'Start', '2019-06-23')
,(5     ,3     ,'Start', '2010-04-20')
,(6     ,3     ,'Failed', '2010-05-10')
,(7     ,4     ,'Start', '2011-01-20')
,(8     ,4     ,'Failed', '2015-01-14')
,(9     ,4     ,'Start', '2016-02-25')
,(10     ,4     ,'Failed', '2019-04-10');

WITH cte AS(
SELECT t.Vehicle_ID, t.stat, t.date_on AS StartDate, ISNULL(LEAD(DATEADD(d, -1, t.date_on)) OVER (PARTITION BY t.Vehicle_ID ORDER BY t.date_on), t.date_on) AS StartDateNext
  FROM @t t
  WHERE t.stat = 'Start'
)
SELECT t.Vehicle_ID
      ,t.StartDate
      ,ISNULL(te.date_on, CAST(GETDATE() AS DATE)) AS FailedRunningDate
      ,ROW_NUMBER() OVER (PARTITION BY t.Vehicle_ID ORDER BY t.StartDate) AS Cycle
  FROM cte t
    LEFT JOIN @t te ON te.Vehicle_ID = t.Vehicle_ID
                  AND te.stat = 'Failed'
                  AND te.date_on >= t.StartDate
                  AND te.date_on <= t.StartDateNext

假设没有任何失败没有开始,你可以通过row_number()

匹配开始/失败
with ordered as(
   SELECT 
    S_No,
    Vehicle_ID,
    date_on,
    status,
    row_number() over(partition by Vehicle_ID, status order by date_on) rn 
   FROM vehicle_table 
   WHERE Vehicle_ID is not null
)
select s.Vehicle_ID, s.date_on start, s.rn cycle, coalesce(f.date_on, getdate()) [Failed/Running]
from ordered s
left join ordered f on s.Vehicle_ID = f.Vehicle_ID and s.rn = f.rn
   and f.status ='Failed'
   -- sanity check 
   and (s.date_on <= f.date_on or f.date_on is null)
where s.status ='Start'
order by s.Vehicle_ID, s.date_on, s.rn

使用ROW_NUMBER()按您想要的方式对数据进行排序

WITH tSortRaw
AS (
    SELECT ROW_NUMBER() OVER (
            PARTITION BY vehicle_id, STATUS 
            ORDER BY date_on DESC
            ) [R],
        *
    FROM Vehicle_Detail
    ),
tMerge
AS (
    SELECT tStart.vehicle_id,
        tStart.date_on [Start],
        IIF(tFailed.date_on IS NULL, GETDATE(), tFailed.date_on) [Failed]
    FROM (
        SELECT *
        FROM tSortRaw
        WHERE STATUS = 'Start'
        ) [tStart]
    LEFT JOIN (
        SELECT *
        FROM tSortRaw
        WHERE STATUS = 'Failed'
        ) [tFailed]
        ON tStart.vehicle_id = tFailed.vehicle_id
            AND tStart.R = tFailed.R
    )
SELECT vehicle_id,
    Start,
    Failed [Failed/Running],
    ROW_NUMBER() OVER (
        PARTITION BY Vehicle_ID
        ORDER BY Start
        ) [Cycle]
FROM tMerge