简体   繁体   English

如何在oracle中根据组中的最小和最大日期获取值?

[英]How to get the values based on min and max date in groups in oracle?

I have a table having data like this:我有一个表,其中包含这样的数据:

Vehicle车辆 Start开始 End结尾 Date日期
Truck A卡车A A一种 B 02/01/2021 01:00:00 02/01/2021 01:00:00
Truck A卡车A B C C 02/01/2021 02:00:00 02/01/2021 02:00:00
Truck A卡车A C C D D 04/01/2021 03:00:00 04/01/2021 03:00:00
Truck B卡车B C C A一种 05/01/2021 01:00:00 05/01/2021 01:00:00
Truck B卡车B A一种 B 06/01/2021 01:00:00 06/01/2021 01:00:00
Truck C卡车 C C C B 07/01/2021 01:00:00 07/01/2021 01:00:00
Truck C卡车 C B C C 08/01/2021 01:00:00 08/01/2021 01:00:00
Truck C卡车 C C C B 09/01/2021 01:00:00 09/01/2021 01:00:00
Truck C卡车 C B A一种 10/01/2021 01:00:00 10/01/2021 01:00:00

I need to get the starting and ending point of each vehicle based on the date.我需要根据日期获取每辆车的起点和终点。

For example, Truck A has started from point A to point B on 02/01/2021 01:00:00.例如,卡车 A 在 02/01/2021 01:00:00 从 A 点出发到 B 点。 Then Truck A has moved from point B to point C on 02/01/2021 02:00:00.然后卡车 A 在 02/01/2021 02:00:00 从 B 点移动到 C 点。 Truck A has moved from point C to point D on 04/01/2021 03:00:00.卡车 A 已于 04/01/2021 03:00:00 从 C 点移动到 D 点。

It has started from point A and ended at point D.它从 A 点开始,在 D 点结束。

I want to get a result like this:我想得到这样的结果:

Vehicle车辆 Start开始 End结尾 Date日期
Truck A卡车A A一种 D D 04/01/2021 03:00:00 04/01/2021 03:00:00

Use GROUP BY and aggregate using KEEP to get the FIRST or LAST date values:使用GROUP BY并使用KEEP聚合以获取FIRSTLAST日期值:

SELECT vehicle,
       MIN("START") KEEP (DENSE_RANK FIRST ORDER BY "DATE") AS "START",
       MAX("END")   KEEP (DENSE_RANK LAST  ORDER BY "DATE") AS "END",
       MAX("DATE") AS "DATE"
FROM   table_name
GROUP BY vehicle

Which, for the sample data:其中,对于样本数据:

CREATE TABLE table_name (Vehicle, "START", "END", "DATE") AS
SELECT 'Truck A', 'A', 'B', DATE '2021-01-02' + INTERVAL '1' HOUR FROM DUAL UNION ALL
SELECT 'Truck A', 'B', 'C', DATE '2021-01-02' + INTERVAL '2' HOUR FROM DUAL UNION ALL
SELECT 'Truck A', 'C', 'D', DATE '2021-01-04' + INTERVAL '3' HOUR FROM DUAL UNION ALL
SELECT 'Truck B', 'C', 'A', DATE '2021-01-05' + INTERVAL '1' HOUR FROM DUAL UNION ALL
SELECT 'Truck B', 'A', 'B', DATE '2021-01-06' + INTERVAL '1' HOUR FROM DUAL UNION ALL
SELECT 'Truck C', 'C', 'B', DATE '2021-01-07' + INTERVAL '1' HOUR FROM DUAL UNION ALL
SELECT 'Truck C', 'B', 'C', DATE '2021-01-08' + INTERVAL '1' HOUR FROM DUAL UNION ALL
SELECT 'Truck C', 'C', 'B', DATE '2021-01-09' + INTERVAL '1' HOUR FROM DUAL UNION ALL
SELECT 'Truck C', 'B', 'A', DATE '2021-01-10' + INTERVAL '1' HOUR FROM DUAL

Outputs:输出:

VEHICLE车辆 START开始 END结尾 DATE日期
Truck A卡车A A一种 D D 2021-01-04 03:00:00 2021-01-04 03:00:00
Truck B卡车B C C B 2021-01-06 01:00:00 2021-01-06 01:00:00
Truck C卡车 C C C A一种 2021-01-10 01:00:00 2021-01-10 01:00:00

db<>fiddle here db<> 在这里小提琴

 WITH CTE(Vehicle,  StartT,     EndD,   DateD) AS
 (

     SELECT 'Truck A', 'A' ,'B',    CAST('02/01/2021 01:00:00'AS SMALLDATETIME)  UNION ALL
     SELECT'Truck A' ,  'B',    'C',    CAST('02/01/2021 02:00:00'AS SMALLDATETIME) UNION ALL
     SELECT'Truck A',   'C' ,   'D',    '04/01/2021 03:00:00' UNION ALL
     SELECT'Truck B',   'C' ,   'A',    '05/01/2021 01:00:00' UNION ALL
     SELECT'Truck B',   'A',    'B',    '06/01/2021 01:00:00' UNION ALL
     SELECT'Truck C',   'C' ,   'B',    '07/01/2021 01:00:00' UNION ALL
     SELECT'Truck C' ,  'B',    'C',    '08/01/2021 01:00:00' UNION ALL
     SELECT'Truck C' ,  'C' ,   'B',    '09/01/2021 01:00:00' UNION ALL
     SELECT'Truck C' ,  'B',    'A',    '10/01/2021 01:00:00'  
  ),
 CTE2(Vehicle,  StartT,     EndD,   DateD,XCOL,YCOL) AS
  (
    SELECT C.Vehicle,C.STARTT,C.ENDD,C.DATED,
     ROW_NUMBER()OVER(PARTITION BY C.Vehicle ORDER BY C.DATED ASC)XCOL,
     ROW_NUMBER()OVER(PARTITION BY C.Vehicle ORDER BY C.DATED DESC)YCOL
     FROM CTE AS C
  )
  SELECT C.VEHICLE,C.StartT,X.EndD,X.DateD
   FROM CTE2 AS C
    JOIN CTE2 AS X ON C.Vehicle=X.Vehicle
     WHERE C.XCOL=1 AND X.YCOL=1

Sorry, I don't have Oracle, so have created the query for MS SQL Server CTE represents your sample data CTE2 calculates "bidirectional" row_number.抱歉,我没有 Oracle,因此创建了 MS SQL Server CTE 查询表示您的示例数据 CTE2 计算“双向”row_number。 For start row(eg for 'TruckA') XCOL=1.对于起始行(例如对于 'TruckA')XCOL=1。 For end row YCOL=1 Then we join these two CTEs on Vehicle.对于 end row YCOL=1 然后我们在 Vehicle 上加入这两个 CTE。 Could you please try this query if it is suitable for you你能试试这个查询是否适合你

I think this solution should work for you, although probably there is a more elegant solution.我认为这个解决方案应该适合你,尽管可能有一个更优雅的解决方案。

with x  ( Vehicle   , Start_Letter  ,End_Letter , Date_Letter  )              
as 
(
select 'Truck A' , 'A' , 'B' , to_date('02/01/2021 01:00:00','dd/mm/yyyy hh24:mi:ss') from dual union all 
select 'Truck A' , 'B' , 'C' , to_date('02/01/2021 02:00:00','dd/mm/yyyy hh24:mi:ss') from dual union all 
select 'Truck A' , 'C' , 'D' , to_date('04/01/2021 03:00:00','dd/mm/yyyy hh24:mi:ss') from dual union all 
select 'Truck B' , 'C' , 'A' , to_date('05/01/2021 01:00:00','dd/mm/yyyy hh24:mi:ss') from dual union all 
select 'Truck B' , 'A' , 'B' , to_date('06/01/2021 01:00:00','dd/mm/yyyy hh24:mi:ss') from dual union all 
select 'Truck C' , 'C' , 'B' , to_date('07/01/2021 01:00:00','dd/mm/yyyy hh24:mi:ss') from dual union all 
select 'Truck C' , 'B' , 'C' , to_date('08/01/2021 01:00:00','dd/mm/yyyy hh24:mi:ss') from dual union all 
select 'Truck C' , 'C' , 'B' , to_date('09/01/2021 01:00:00','dd/mm/yyyy hh24:mi:ss') from dual union all 
select 'Truck C' , 'B' , 'A' , to_date('10/01/2021 01:00:00','dd/mm/yyyy hh24:mi:ss') from dual 
) 
select vehicle , start_letter, end_letter, date_letter from 
(
select vehicle , min_start_lett as start_letter, max_start_lett as end_letter, date_letter, 
row_number() over(partition by vehicle order by date_letter desc) as ranking
from 
( 
select x.* , 
rank() over(partition by vehicle order by start_letter desc, end_letter desc, date_letter desc ) as rn , 
min(start_letter) over(partition by vehicle) as min_start_lett , 
max(end_letter) over(partition by vehicle) as max_start_lett
from x 
) d 
where rn = ( select max(rn) from x c where c.vehicle = d.vehicle group by vehicle )             
) where ranking = 1 
;

在此处输入图片说明

db<>fiddle 数据库<>小提琴

Using the window function FIRST_VALUE to find the first and last for each vehicle使用窗函数 FIRST_VALUE 查找每辆车的第一个和最后一个

SELECT Vehicle
, FirstStart AS "Start"
, LastEnd AS "End"
, MAX("Date") AS "Date"
FROM
(
  SELECT Vehicle, "Start", "End", "Date"
  , FIRST_VALUE("Start") OVER (PARTITION BY Vehicle ORDER BY "Date") AS FirstStart
  , FIRST_VALUE("End") OVER (PARTITION BY Vehicle ORDER BY "Date" DESC) AS LastEnd
  FROM yourtable
) q
GROUP BY Vehicle, FirstStart, LastEnd
ORDER BY Vehicle;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM