oracle Select 1 分钟内售出商品的日期
oracle Select dates for items sold within 1 minute of each other
Oracle 12c 数据库。
我有汽车销售table:
CREATE TABLE CAR_SALES
( NUM_CARS NUMBER(10,0),
EQUIPMENT_TYPE VARCHAR2(100),
LOCATION VARCHAR2(500),
SOLD_DATE DATE
) ;
--Insert sample data
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('8','Rovers','coventry','07-SEP-19 10:00:12');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('1','Rovers','coventry','07-SEP-19 10:00:45');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('9','Jaguars','coventry','07-SEP-19 06:00:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('7','Rovers','leamington','30-AUG-19 13:10:13');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('10','Trans Am','leamington','30-AUG-19 09:00:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('2','Trans Am','leamington','30-AUG-19 13:10:48');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('8','Rovers','coventry','06-SEP-19 18:00:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('4','Rovers','leamington','06-SEP-19 09:00:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('100','Trans Am','leamington','06-SEP-19 08:59:45');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('1','corvette','leamington','06-SEP-19 09:00:10');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('2','Toyota','coventry','06-SEP-19 10:00:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('15','Rovers','coventry','07-SEP-19 11:05:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('2','Jaguars','coventry','07-SEP-19 17:02:07');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('3','Trans Am','leamington','30-AUG-19 13:10:25');
commit;
我只需要 select 某个地点在 1 分钟内发生的销售额(销售日期)。
我创建了以下 sql 示例,但它不仅显示某个位置的销售日期在 1 分钟内的记录,它还显示了某个位置的所有记录。另外,是否可以通过 location|equipment_type 创建结果集的 listagg 以匹配 1 分钟内的日期?我不知道如何获得结果然后将这些结果显示为:
1分钟以内的记录:
coventry 07-SEP-19 10:00:45 Rovers
coventry 07-SEP-19 10:00:12 Rovers
Listagg 将是:
LOCATION listagg(EQUIPMENT_TYPE)
coventry Rovers,Rovers
-- 这个例子中的 equipment_type 恰好是漫游者,漫游者,它将是任何 equipment_type 加上匹配的 1 分钟销售。
SQL>
select location,sold_date,equipment_type,num_cars
from car_sales c
where exists( select 'X'
from car_sales x
where c.location=x.location
and c.equipment_type=x.equipment_type
and c.sold_date between x.sold_date - interval '1' MINUTE
and x.sold_date + interval '1' MINUTE
)
group by location,sold_date,equipment_type,num_cars
order by sold_date desc;
我怎样才能创建正确的结果,并按位置列出在 60 秒内有销售额的 equipment_type 个结果。
提前谢谢你。
吉莉
您可以使用 LISTAGG(equipment_type,',') WITHIN GROUP (ORDER BY <sold_date_to_minute_precision>)
并将其他 (non-aggregated) 列添加到 GROUP BY 列表中:
SELECT location, TO_CHAR(sold_date,'yyyy-mm-dd hh24:mi') AS sold_date_minutes,
LISTAGG(equipment_type,',') WITHIN GROUP
( ORDER BY location, TO_DATE(sold_date,'yyyy-mm-dd hh24:mi') ) AS equipment_type
FROM car_sales c
GROUP BY location, TO_CHAR(sold_date,'yyyy-mm-dd hh24:mi')
在 Oracle 中,您可以使用 TRUNC 函数将日期截断为分钟。然后您可以按该值分组以查找在同一分钟内售出的任何汽车。
SELECT location,
TO_CHAR (TRUNC (sold_date, 'MI'), 'DD-MON-YYYY HH:MI PM') AS sold_minute,
LISTAGG (equipment_type, ',') as equipment_list
FROM car_sales
GROUP BY location, TRUNC (sold_date, 'MI')
HAVING COUNT (*) > 1;
您可以使用LAG
/LEAD
解析函数来比较前后行以确定它们是否在当前行的一分钟内:
SELECT location,
LISTAGG( equipment_type, ',' )
WITHIN GROUP ( ORDER BY sold_date )
AS equipment_types,
LISTAGG( TO_CHAR( sold_date, 'HH24:MI:SS' ), ',' )
WITHIN GROUP ( ORDER BY sold_date )
AS sold_dates
FROM (
SELECT num_cars,
equipment_type,
location,
sold_date,
CASE
WHEN within_minute_of_prev = 1 OR within_minute_of_next = 1
THEN SUM(
CASE
WHEN within_minute_of_prev = 0 AND within_minute_of_next = 1
THEN 1
ELSE 0
END
) OVER ( PARTITION BY location ORDER BY sold_date )
END AS grp
FROM (
SELECT c.*,
CASE
WHEN ( sold_date
- LAG( sold_date ) OVER ( PARTITION BY location ORDER BY sold_date )
) DAY TO SECOND
<= INTERVAL '1' MINUTE
THEN 1
ELSE 0
END AS within_minute_of_prev,
CASE
WHEN ( LEAD( sold_date ) OVER ( PARTITION BY location ORDER BY sold_date )
- sold_date
) DAY TO SECOND
<= INTERVAL '1' MINUTE
THEN 1
ELSE 0
END AS within_minute_of_next
FROM car_sales c
)
)
WHERE grp IS NOT NULL
GROUP BY location, grp;
其中,对于您的样本数据:
CREATE TABLE CAR_SALES ( NUM_CARS, EQUIPMENT_TYPE, LOCATION, SOLD_DATE ) AS
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 9, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '06:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 7, 'Rovers', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:13' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 10, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-06' + INTERVAL '18:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 4, 'Rovers', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 100, 'Trans Am', 'leamington', DATE '2019-09-06' + INTERVAL '08:59:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'corvette', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:10' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Toyota', 'coventry', DATE '2019-09-06' + INTERVAL '10:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 15, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '11:05:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '17:02:07' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:25' HOUR TO SECOND FROM DUAL;
输出:
LOCATION | EQUIPMENT_TYPES | SOLD_DATES
:--------- | :----------------------- | :-------------------------
coventry | Rovers,Rovers | 10:00:12,10:00:45
leamington | Rovers,Trans Am,Trans Am | 13:10:13,13:10:25,13:10:48
leamington | Trans Am,Rovers,corvette | 08:59:45,09:00:00,09:00:10
db<>fiddle here
更新
一个更短的 Oracle 12c 查询使用 MATCH_RECOGNIZE
:
SELECT location,
LISTAGG( equipment_type, ',' )
WITHIN GROUP ( ORDER BY sold_date )
AS equipment_types,
LISTAGG( TO_CHAR( sold_date, 'HH24:MI:SS' ), ',' )
WITHIN GROUP ( ORDER BY sold_date )
AS sold_times
FROM car_sales
MATCH_RECOGNIZE (
PARTITION BY location
ORDER BY sold_date
MEASURES
MATCH_NUMBER() AS mno
ALL ROWS PER MATCH
PATTERN (A B+)
DEFINE
B AS B.sold_date <= PREV(B.sold_date) + interval '1' minute
)
GROUP BY location, mno
ORDER BY location, mno;
其中,对于测试数据:
CREATE TABLE CAR_SALES ( NUM_CARS, EQUIPMENT_TYPE, LOCATION, SOLD_DATE ) AS
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:15' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:30' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 9, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '06:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 7, 'Rovers', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:13' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 10, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-06' + INTERVAL '18:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 4, 'Rovers', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 100, 'Trans Am', 'leamington', DATE '2019-09-06' + INTERVAL '08:59:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'corvette', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:10' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Toyota', 'coventry', DATE '2019-09-06' + INTERVAL '10:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 15, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '11:05:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '17:02:07' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:25' HOUR TO SECOND FROM DUAL;
输出:
LOCATION | EQUIPMENT_TYPES | SOLD_TIMES
:--------- | :-------------------------- | :----------------------------------
coventry | Rovers,Rovers,Rovers,Rovers | 10:00:12,10:00:45,10:01:15,10:01:30
leamington | Rovers,Trans Am,Trans Am | 13:10:13,13:10:25,13:10:48
leamington | Trans Am,Rovers,corvette | 08:59:45,09:00:00,09:00:10
db<>fiddle here
我还没有得到答案,例如,如何聚合多行链,其中每一行都比前一行早不到一分钟,例如
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:15' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:30' HOUR TO SECOND FROM DUAL
由于您已经有了一个将所有这些值聚合到一组的解决方案(即 10:01:30-10:00:12 > 1 分钟,但它们仍在同一组中),我将展示如何获得第一次和最后一次销售之间的最大差异 <= 1 分钟的组。
在这种情况下,最好使用 range between current row and interval '1' minute following
的解析函数。例如,对于每次销售,我们可以很容易地获得下一分钟同一地点的销售量:
with CAR_SALES ( NUM_CARS, EQUIPMENT_TYPE, LOCATION, SOLD_DATE ) AS (
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:15' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:30' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 9, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '06:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 7, 'Rovers', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:13' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 10, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-06' + INTERVAL '18:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 4, 'Rovers', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 100, 'Trans Am', 'leamington', DATE '2019-09-06' + INTERVAL '08:59:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'corvette', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:10' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Toyota', 'coventry', DATE '2019-09-06' + INTERVAL '10:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 15, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '11:05:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '17:02:07' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:25' HOUR TO SECOND FROM DUAL
)
SELECT
location,
num_cars,
equipment_type,
sold_date,
count(*)over(partition by LOCATION order by SOLD_DATE range between current row and interval'1' minute following) cnt
from car_sales
order by location,sold_date;
我添加了几行,以便更容易看出差异。
结果:
LOCATION NUM_CARS EQUIPMEN SOLD_DATE CNT
---------- ---------- -------- ------------------- ----------
coventry 2 Toyota 2019-09-06 10:00:00 1
coventry 8 Rovers 2019-09-06 18:00:00 1
coventry 9 Jaguars 2019-09-07 06:00:00 1
coventry 1 Rovers 2019-09-07 10:00:12 2
coventry 2 Rovers 2019-09-07 10:00:45 3
coventry 3 Rovers 2019-09-07 10:01:15 2
coventry 3 Rovers 2019-09-07 10:01:30 1
coventry 15 Rovers 2019-09-07 11:05:00 1
coventry 2 Jaguars 2019-09-07 17:02:07 1
leamington 10 Trans Am 2019-08-30 09:00:00 1
leamington 7 Rovers 2019-08-30 13:10:13 3
leamington 3 Trans Am 2019-08-30 13:10:25 2
leamington 2 Trans Am 2019-08-30 13:10:48 1
leamington 100 Trans Am 2019-09-06 08:59:45 3
leamington 4 Rovers 2019-09-06 09:00:00 2
leamington 1 corvette 2019-09-06 09:00:10 1
16 rows selected.
此外,我们还可以轻松检查前面的行并仅过滤那些 cnt_preceding>1 或 cnt_following>1 的行,即邻居 <= 1 分钟的行:
select *
from (
SELECT
location,
num_cars,
equipment_type,
sold_date,
count(*)over(partition by LOCATION order by SOLD_DATE range between interval'1' minute preceding and current row) cnt_preceding,
count(*)over(partition by LOCATION order by SOLD_DATE range between current row and interval'1' minute following) cnt_following
from car_sales
)
where
cnt_preceding > 1
or cnt_following > 1
order by location, sold_date;
结果:https://dbfiddle.uk/?rdbms=oracle_18&fiddle=000865dd639ab8d6d6e9fbf64100fcf0
LOCATION NUM_CARS EQUIPMEN SOLD_DATE CNT_PRECEDING CNT_FOLLOWING
---------- ---------- -------- ------------------- ------------- -------------
coventry 1 Rovers 2019-09-07 10:00:12 1 2
coventry 2 Rovers 2019-09-07 10:00:45 2 3
coventry 3 Rovers 2019-09-07 10:01:15 2 2
coventry 3 Rovers 2019-09-07 10:01:30 3 1
leamington 7 Rovers 2019-08-30 13:10:13 1 3
leamington 3 Trans Am 2019-08-30 13:10:25 2 2
leamington 2 Trans Am 2019-08-30 13:10:48 3 1
leamington 100 Trans Am 2019-09-06 08:59:45 1 3
leamington 4 Rovers 2019-09-06 09:00:00 2 2
leamington 1 corvette 2019-09-06 09:00:10 3 1
所以我们现在唯一需要做的就是按 non-overlapping 间隔 <= 1 分钟聚合它们。我将使用另一种方法展示它 - MATCH_RECOGNIZE 子句:
with CAR_SALES ( NUM_CARS, EQUIPMENT_TYPE, LOCATION, SOLD_DATE ) AS (
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:15' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:30' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 9, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '06:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 7, 'Rovers', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:13' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 10, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-06' + INTERVAL '18:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 4, 'Rovers', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 100, 'Trans Am', 'leamington', DATE '2019-09-06' + INTERVAL '08:59:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'corvette', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:10' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Toyota', 'coventry', DATE '2019-09-06' + INTERVAL '10:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 15, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '11:05:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '17:02:07' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:25' HOUR TO SECOND FROM DUAL
)
select *
from car_sales
match_recognize (
partition by location
order by sold_date
MEASURES
FIRST(A.SOLD_DATE) dt_strt,
LAST(SOLD_DATE) dt_end,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls
ALL ROWS PER MATCH
PATTERN (A B+)
DEFINE
B AS B.sold_date < first(A.sold_date) + interval '1' minute
)
order by location, sold_date
;
结果:
LOCATION SOLD_DATE DT_STRT DT_END MNO CLS NUM_CARS EQUIPMEN
---------- ------------------- ------------------- ------------------- ---------- ----- ---------- --------
coventry 2019-09-07 10:00:12 2019-09-07 10:00:12 2019-09-07 10:00:12 1 A 1 Rovers
coventry 2019-09-07 10:00:45 2019-09-07 10:00:12 2019-09-07 10:00:45 1 B 2 Rovers
coventry 2019-09-07 10:01:15 2019-09-07 10:01:15 2019-09-07 10:01:15 2 A 3 Rovers
coventry 2019-09-07 10:01:30 2019-09-07 10:01:15 2019-09-07 10:01:30 2 B 3 Rovers
leamington 2019-08-30 13:10:13 2019-08-30 13:10:13 2019-08-30 13:10:13 1 A 7 Rovers
leamington 2019-08-30 13:10:25 2019-08-30 13:10:13 2019-08-30 13:10:25 1 B 3 Trans Am
leamington 2019-08-30 13:10:48 2019-08-30 13:10:13 2019-08-30 13:10:48 1 B 2 Trans Am
leamington 2019-09-06 08:59:45 2019-09-06 08:59:45 2019-09-06 08:59:45 2 A 100 Trans Am
leamington 2019-09-06 09:00:00 2019-09-06 08:59:45 2019-09-06 09:00:00 2 B 4 Rovers
leamington 2019-09-06 09:00:10 2019-09-06 08:59:45 2019-09-06 09:00:10 2 B 1 corvette
10 rows selected.
你可以看到MNO return MATCH_NUMBER(),即这个位置的群号,所以现在我们可以轻松聚合这些群:
with CAR_SALES ( NUM_CARS, EQUIPMENT_TYPE, LOCATION, SOLD_DATE ) AS (
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:15' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:30' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 9, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '06:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 7, 'Rovers', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:13' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 10, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-06' + INTERVAL '18:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 4, 'Rovers', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 100, 'Trans Am', 'leamington', DATE '2019-09-06' + INTERVAL '08:59:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'corvette', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:10' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Toyota', 'coventry', DATE '2019-09-06' + INTERVAL '10:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 15, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '11:05:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '17:02:07' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:25' HOUR TO SECOND FROM DUAL
)
,matches as (
select *
from car_sales
match_recognize (
partition by location
order by sold_date
MEASURES
FIRST(A.SOLD_DATE) dt_strt,
LAST(SOLD_DATE) dt_end,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls
ALL ROWS PER MATCH
PATTERN (A B+)
DEFINE
B AS B.sold_date < first(A.sold_date) + interval '1' minute
)
)
select
location,
mno,
dt_strt,
listagg(EQUIPMENT_TYPE,',')
within group(order by sold_date) EQUIPMENT_TYPEs,
listagg(to_char(sold_date,'hh24:mi:ss'),',')
within group(order by sold_date) sold_dates
from matches
group by
location,
mno,
dt_strt
order by 1,2
;
带有结果的完整测试用例:https://dbfiddle.uk/?rdbms=oracle_18&fiddle=d2594a250f9adb5a9f290d7f72be2e05
LOCATION MNO DT_STRT EQUIPMENT_TYPES SOLD_DATES
---------- ---------- ------------------- ---------------------------------------- --------------------------------------------------
coventry 1 2019-09-07 10:00:12 Rovers,Rovers 10:00:12,10:00:45
coventry 2 2019-09-07 10:01:15 Rovers,Rovers 10:01:15,10:01:30
leamington 1 2019-08-30 13:10:13 Rovers,Trans Am,Trans Am 13:10:13,13:10:25,13:10:48
leamington 2 2019-09-06 08:59:45 Trans Am,Rovers,corvette 08:59:45,09:00:00,09:00:10
Oracle 12c 数据库。
我有汽车销售table:
CREATE TABLE CAR_SALES
( NUM_CARS NUMBER(10,0),
EQUIPMENT_TYPE VARCHAR2(100),
LOCATION VARCHAR2(500),
SOLD_DATE DATE
) ;
--Insert sample data
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('8','Rovers','coventry','07-SEP-19 10:00:12');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('1','Rovers','coventry','07-SEP-19 10:00:45');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('9','Jaguars','coventry','07-SEP-19 06:00:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('7','Rovers','leamington','30-AUG-19 13:10:13');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('10','Trans Am','leamington','30-AUG-19 09:00:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('2','Trans Am','leamington','30-AUG-19 13:10:48');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('8','Rovers','coventry','06-SEP-19 18:00:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('4','Rovers','leamington','06-SEP-19 09:00:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('100','Trans Am','leamington','06-SEP-19 08:59:45');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('1','corvette','leamington','06-SEP-19 09:00:10');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('2','Toyota','coventry','06-SEP-19 10:00:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('15','Rovers','coventry','07-SEP-19 11:05:00');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('2','Jaguars','coventry','07-SEP-19 17:02:07');
insert into car_sales (num_cars,equipment_type,location,sold_date) values ('3','Trans Am','leamington','30-AUG-19 13:10:25');
commit;
我只需要 select 某个地点在 1 分钟内发生的销售额(销售日期)。
我创建了以下 sql 示例,但它不仅显示某个位置的销售日期在 1 分钟内的记录,它还显示了某个位置的所有记录。另外,是否可以通过 location|equipment_type 创建结果集的 listagg 以匹配 1 分钟内的日期?我不知道如何获得结果然后将这些结果显示为:
1分钟以内的记录:
coventry 07-SEP-19 10:00:45 Rovers
coventry 07-SEP-19 10:00:12 Rovers
Listagg 将是:
LOCATION listagg(EQUIPMENT_TYPE)
coventry Rovers,Rovers
-- 这个例子中的 equipment_type 恰好是漫游者,漫游者,它将是任何 equipment_type 加上匹配的 1 分钟销售。
SQL>
select location,sold_date,equipment_type,num_cars
from car_sales c
where exists( select 'X'
from car_sales x
where c.location=x.location
and c.equipment_type=x.equipment_type
and c.sold_date between x.sold_date - interval '1' MINUTE
and x.sold_date + interval '1' MINUTE
)
group by location,sold_date,equipment_type,num_cars
order by sold_date desc;
我怎样才能创建正确的结果,并按位置列出在 60 秒内有销售额的 equipment_type 个结果。
提前谢谢你。 吉莉
您可以使用 LISTAGG(equipment_type,',') WITHIN GROUP (ORDER BY <sold_date_to_minute_precision>)
并将其他 (non-aggregated) 列添加到 GROUP BY 列表中:
SELECT location, TO_CHAR(sold_date,'yyyy-mm-dd hh24:mi') AS sold_date_minutes,
LISTAGG(equipment_type,',') WITHIN GROUP
( ORDER BY location, TO_DATE(sold_date,'yyyy-mm-dd hh24:mi') ) AS equipment_type
FROM car_sales c
GROUP BY location, TO_CHAR(sold_date,'yyyy-mm-dd hh24:mi')
在 Oracle 中,您可以使用 TRUNC 函数将日期截断为分钟。然后您可以按该值分组以查找在同一分钟内售出的任何汽车。
SELECT location,
TO_CHAR (TRUNC (sold_date, 'MI'), 'DD-MON-YYYY HH:MI PM') AS sold_minute,
LISTAGG (equipment_type, ',') as equipment_list
FROM car_sales
GROUP BY location, TRUNC (sold_date, 'MI')
HAVING COUNT (*) > 1;
您可以使用LAG
/LEAD
解析函数来比较前后行以确定它们是否在当前行的一分钟内:
SELECT location,
LISTAGG( equipment_type, ',' )
WITHIN GROUP ( ORDER BY sold_date )
AS equipment_types,
LISTAGG( TO_CHAR( sold_date, 'HH24:MI:SS' ), ',' )
WITHIN GROUP ( ORDER BY sold_date )
AS sold_dates
FROM (
SELECT num_cars,
equipment_type,
location,
sold_date,
CASE
WHEN within_minute_of_prev = 1 OR within_minute_of_next = 1
THEN SUM(
CASE
WHEN within_minute_of_prev = 0 AND within_minute_of_next = 1
THEN 1
ELSE 0
END
) OVER ( PARTITION BY location ORDER BY sold_date )
END AS grp
FROM (
SELECT c.*,
CASE
WHEN ( sold_date
- LAG( sold_date ) OVER ( PARTITION BY location ORDER BY sold_date )
) DAY TO SECOND
<= INTERVAL '1' MINUTE
THEN 1
ELSE 0
END AS within_minute_of_prev,
CASE
WHEN ( LEAD( sold_date ) OVER ( PARTITION BY location ORDER BY sold_date )
- sold_date
) DAY TO SECOND
<= INTERVAL '1' MINUTE
THEN 1
ELSE 0
END AS within_minute_of_next
FROM car_sales c
)
)
WHERE grp IS NOT NULL
GROUP BY location, grp;
其中,对于您的样本数据:
CREATE TABLE CAR_SALES ( NUM_CARS, EQUIPMENT_TYPE, LOCATION, SOLD_DATE ) AS
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 9, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '06:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 7, 'Rovers', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:13' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 10, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-06' + INTERVAL '18:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 4, 'Rovers', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 100, 'Trans Am', 'leamington', DATE '2019-09-06' + INTERVAL '08:59:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'corvette', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:10' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Toyota', 'coventry', DATE '2019-09-06' + INTERVAL '10:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 15, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '11:05:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '17:02:07' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:25' HOUR TO SECOND FROM DUAL;
输出:
LOCATION | EQUIPMENT_TYPES | SOLD_DATES :--------- | :----------------------- | :------------------------- coventry | Rovers,Rovers | 10:00:12,10:00:45 leamington | Rovers,Trans Am,Trans Am | 13:10:13,13:10:25,13:10:48 leamington | Trans Am,Rovers,corvette | 08:59:45,09:00:00,09:00:10
db<>fiddle here
更新
一个更短的 Oracle 12c 查询使用 MATCH_RECOGNIZE
:
SELECT location,
LISTAGG( equipment_type, ',' )
WITHIN GROUP ( ORDER BY sold_date )
AS equipment_types,
LISTAGG( TO_CHAR( sold_date, 'HH24:MI:SS' ), ',' )
WITHIN GROUP ( ORDER BY sold_date )
AS sold_times
FROM car_sales
MATCH_RECOGNIZE (
PARTITION BY location
ORDER BY sold_date
MEASURES
MATCH_NUMBER() AS mno
ALL ROWS PER MATCH
PATTERN (A B+)
DEFINE
B AS B.sold_date <= PREV(B.sold_date) + interval '1' minute
)
GROUP BY location, mno
ORDER BY location, mno;
其中,对于测试数据:
CREATE TABLE CAR_SALES ( NUM_CARS, EQUIPMENT_TYPE, LOCATION, SOLD_DATE ) AS
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:15' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:30' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 9, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '06:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 7, 'Rovers', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:13' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 10, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-06' + INTERVAL '18:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 4, 'Rovers', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 100, 'Trans Am', 'leamington', DATE '2019-09-06' + INTERVAL '08:59:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'corvette', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:10' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Toyota', 'coventry', DATE '2019-09-06' + INTERVAL '10:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 15, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '11:05:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '17:02:07' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:25' HOUR TO SECOND FROM DUAL;
输出:
LOCATION | EQUIPMENT_TYPES | SOLD_TIMES :--------- | :-------------------------- | :---------------------------------- coventry | Rovers,Rovers,Rovers,Rovers | 10:00:12,10:00:45,10:01:15,10:01:30 leamington | Rovers,Trans Am,Trans Am | 13:10:13,13:10:25,13:10:48 leamington | Trans Am,Rovers,corvette | 08:59:45,09:00:00,09:00:10
db<>fiddle here
我还没有得到答案,例如,如何聚合多行链,其中每一行都比前一行早不到一分钟,例如
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:15' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:30' HOUR TO SECOND FROM DUAL
由于您已经有了一个将所有这些值聚合到一组的解决方案(即 10:01:30-10:00:12 > 1 分钟,但它们仍在同一组中),我将展示如何获得第一次和最后一次销售之间的最大差异 <= 1 分钟的组。
在这种情况下,最好使用 range between current row and interval '1' minute following
的解析函数。例如,对于每次销售,我们可以很容易地获得下一分钟同一地点的销售量:
with CAR_SALES ( NUM_CARS, EQUIPMENT_TYPE, LOCATION, SOLD_DATE ) AS (
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:15' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:30' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 9, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '06:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 7, 'Rovers', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:13' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 10, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-06' + INTERVAL '18:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 4, 'Rovers', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 100, 'Trans Am', 'leamington', DATE '2019-09-06' + INTERVAL '08:59:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'corvette', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:10' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Toyota', 'coventry', DATE '2019-09-06' + INTERVAL '10:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 15, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '11:05:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '17:02:07' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:25' HOUR TO SECOND FROM DUAL
)
SELECT
location,
num_cars,
equipment_type,
sold_date,
count(*)over(partition by LOCATION order by SOLD_DATE range between current row and interval'1' minute following) cnt
from car_sales
order by location,sold_date;
我添加了几行,以便更容易看出差异。 结果:
LOCATION NUM_CARS EQUIPMEN SOLD_DATE CNT
---------- ---------- -------- ------------------- ----------
coventry 2 Toyota 2019-09-06 10:00:00 1
coventry 8 Rovers 2019-09-06 18:00:00 1
coventry 9 Jaguars 2019-09-07 06:00:00 1
coventry 1 Rovers 2019-09-07 10:00:12 2
coventry 2 Rovers 2019-09-07 10:00:45 3
coventry 3 Rovers 2019-09-07 10:01:15 2
coventry 3 Rovers 2019-09-07 10:01:30 1
coventry 15 Rovers 2019-09-07 11:05:00 1
coventry 2 Jaguars 2019-09-07 17:02:07 1
leamington 10 Trans Am 2019-08-30 09:00:00 1
leamington 7 Rovers 2019-08-30 13:10:13 3
leamington 3 Trans Am 2019-08-30 13:10:25 2
leamington 2 Trans Am 2019-08-30 13:10:48 1
leamington 100 Trans Am 2019-09-06 08:59:45 3
leamington 4 Rovers 2019-09-06 09:00:00 2
leamington 1 corvette 2019-09-06 09:00:10 1
16 rows selected.
此外,我们还可以轻松检查前面的行并仅过滤那些 cnt_preceding>1 或 cnt_following>1 的行,即邻居 <= 1 分钟的行:
select *
from (
SELECT
location,
num_cars,
equipment_type,
sold_date,
count(*)over(partition by LOCATION order by SOLD_DATE range between interval'1' minute preceding and current row) cnt_preceding,
count(*)over(partition by LOCATION order by SOLD_DATE range between current row and interval'1' minute following) cnt_following
from car_sales
)
where
cnt_preceding > 1
or cnt_following > 1
order by location, sold_date;
结果:https://dbfiddle.uk/?rdbms=oracle_18&fiddle=000865dd639ab8d6d6e9fbf64100fcf0
LOCATION NUM_CARS EQUIPMEN SOLD_DATE CNT_PRECEDING CNT_FOLLOWING
---------- ---------- -------- ------------------- ------------- -------------
coventry 1 Rovers 2019-09-07 10:00:12 1 2
coventry 2 Rovers 2019-09-07 10:00:45 2 3
coventry 3 Rovers 2019-09-07 10:01:15 2 2
coventry 3 Rovers 2019-09-07 10:01:30 3 1
leamington 7 Rovers 2019-08-30 13:10:13 1 3
leamington 3 Trans Am 2019-08-30 13:10:25 2 2
leamington 2 Trans Am 2019-08-30 13:10:48 3 1
leamington 100 Trans Am 2019-09-06 08:59:45 1 3
leamington 4 Rovers 2019-09-06 09:00:00 2 2
leamington 1 corvette 2019-09-06 09:00:10 3 1
所以我们现在唯一需要做的就是按 non-overlapping 间隔 <= 1 分钟聚合它们。我将使用另一种方法展示它 - MATCH_RECOGNIZE 子句:
with CAR_SALES ( NUM_CARS, EQUIPMENT_TYPE, LOCATION, SOLD_DATE ) AS (
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:15' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:30' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 9, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '06:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 7, 'Rovers', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:13' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 10, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-06' + INTERVAL '18:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 4, 'Rovers', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 100, 'Trans Am', 'leamington', DATE '2019-09-06' + INTERVAL '08:59:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'corvette', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:10' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Toyota', 'coventry', DATE '2019-09-06' + INTERVAL '10:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 15, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '11:05:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '17:02:07' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:25' HOUR TO SECOND FROM DUAL
)
select *
from car_sales
match_recognize (
partition by location
order by sold_date
MEASURES
FIRST(A.SOLD_DATE) dt_strt,
LAST(SOLD_DATE) dt_end,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls
ALL ROWS PER MATCH
PATTERN (A B+)
DEFINE
B AS B.sold_date < first(A.sold_date) + interval '1' minute
)
order by location, sold_date
;
结果:
LOCATION SOLD_DATE DT_STRT DT_END MNO CLS NUM_CARS EQUIPMEN
---------- ------------------- ------------------- ------------------- ---------- ----- ---------- --------
coventry 2019-09-07 10:00:12 2019-09-07 10:00:12 2019-09-07 10:00:12 1 A 1 Rovers
coventry 2019-09-07 10:00:45 2019-09-07 10:00:12 2019-09-07 10:00:45 1 B 2 Rovers
coventry 2019-09-07 10:01:15 2019-09-07 10:01:15 2019-09-07 10:01:15 2 A 3 Rovers
coventry 2019-09-07 10:01:30 2019-09-07 10:01:15 2019-09-07 10:01:30 2 B 3 Rovers
leamington 2019-08-30 13:10:13 2019-08-30 13:10:13 2019-08-30 13:10:13 1 A 7 Rovers
leamington 2019-08-30 13:10:25 2019-08-30 13:10:13 2019-08-30 13:10:25 1 B 3 Trans Am
leamington 2019-08-30 13:10:48 2019-08-30 13:10:13 2019-08-30 13:10:48 1 B 2 Trans Am
leamington 2019-09-06 08:59:45 2019-09-06 08:59:45 2019-09-06 08:59:45 2 A 100 Trans Am
leamington 2019-09-06 09:00:00 2019-09-06 08:59:45 2019-09-06 09:00:00 2 B 4 Rovers
leamington 2019-09-06 09:00:10 2019-09-06 08:59:45 2019-09-06 09:00:10 2 B 1 corvette
10 rows selected.
你可以看到MNO return MATCH_NUMBER(),即这个位置的群号,所以现在我们可以轻松聚合这些群:
with CAR_SALES ( NUM_CARS, EQUIPMENT_TYPE, LOCATION, SOLD_DATE ) AS (
SELECT 1, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:12' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:00:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:15' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '10:01:30' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 9, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '06:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 7, 'Rovers', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:13' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 10, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'Rovers', 'coventry', DATE '2019-09-06' + INTERVAL '18:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 4, 'Rovers', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 100, 'Trans Am', 'leamington', DATE '2019-09-06' + INTERVAL '08:59:45' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 1, 'corvette', 'leamington', DATE '2019-09-06' + INTERVAL '09:00:10' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Toyota', 'coventry', DATE '2019-09-06' + INTERVAL '10:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 15, 'Rovers', 'coventry', DATE '2019-09-07' + INTERVAL '11:05:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 2, 'Jaguars', 'coventry', DATE '2019-09-07' + INTERVAL '17:02:07' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 3, 'Trans Am', 'leamington', DATE '2019-08-30' + INTERVAL '13:10:25' HOUR TO SECOND FROM DUAL
)
,matches as (
select *
from car_sales
match_recognize (
partition by location
order by sold_date
MEASURES
FIRST(A.SOLD_DATE) dt_strt,
LAST(SOLD_DATE) dt_end,
MATCH_NUMBER() AS mno,
CLASSIFIER() AS cls
ALL ROWS PER MATCH
PATTERN (A B+)
DEFINE
B AS B.sold_date < first(A.sold_date) + interval '1' minute
)
)
select
location,
mno,
dt_strt,
listagg(EQUIPMENT_TYPE,',')
within group(order by sold_date) EQUIPMENT_TYPEs,
listagg(to_char(sold_date,'hh24:mi:ss'),',')
within group(order by sold_date) sold_dates
from matches
group by
location,
mno,
dt_strt
order by 1,2
;
带有结果的完整测试用例:https://dbfiddle.uk/?rdbms=oracle_18&fiddle=d2594a250f9adb5a9f290d7f72be2e05
LOCATION MNO DT_STRT EQUIPMENT_TYPES SOLD_DATES
---------- ---------- ------------------- ---------------------------------------- --------------------------------------------------
coventry 1 2019-09-07 10:00:12 Rovers,Rovers 10:00:12,10:00:45
coventry 2 2019-09-07 10:01:15 Rovers,Rovers 10:01:15,10:01:30
leamington 1 2019-08-30 13:10:13 Rovers,Trans Am,Trans Am 13:10:13,13:10:25,13:10:48
leamington 2 2019-09-06 08:59:45 Trans Am,Rovers,corvette 08:59:45,09:00:00,09:00:10