计算日期之间可用的周期数并将行值排列为列值
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
我在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