【问题标题】:oracle Select dates for items sold within 1 minute of each otheroracle 为在 1 分钟内出售的商品选择日期
【发布时间】:2020-09-16 19:28:29
【问题描述】:

Oracle 12c 数据库。

我有一张汽车销售表:

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;

我只需选择某个地点在 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  

-- 本例中的设备类型恰好是 rover,rover,它可以是匹配的 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 秒内有销售额的设备类型的结果。

提前谢谢你。 吉利

【问题讨论】:

  • 只是一个侧面观察 - 您将 SOLD_DATE 设为 DATE 数据类型是件好事。这是应该的。但是随后您插入了一个字符串,强制 oracle 执行隐含的 TO_DATE,以便将其转换为 oracle 的内部二进制格式的 DATE。也许你很幸运 NLS_DATE_FORMAT 匹配,但你不应该依赖运气。此外,您应该始终指定 4 位数的年份。您的 INSERT 应该是:插入 car_sales (num_cars,equipment_type,location,sold_date) 值 ('8','Rovers','coventry',to_date('07-SEP-2019 10:00:12',dd-MON- yyyy hh24:mi:ss');
  • 感谢 Ed 的建议,我同意 YYYY 年。 :-)
  • 10:00:00, 10:00:30,10:01:00,10:01:30 的情况下你想要什么结果?您想汇总所有这些吗?
  • @SayanMalakshinov 10:00:1210:00:45 彼此相距一分钟以内,应该在同一组中,10:00:4510:01:15 彼此相距一分钟以内。您可以: 将所有 3 个放在同一个组中(即使最高和最低的距离不在一分钟之内);或者,重复行,以便中间值可以分为 2 组;或者有一种方法可以只为一个组选择某些值,同时排除其他潜在的分组(例如在一小时后的同一分钟内分组)。其中任何一个都是潜在有效的解决方案。
  • 我添加了一个可能的解决方案,其间隔时间不超过一分钟

标签: sql oracle date seconds listagg


【解决方案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;

输出:

位置 | EQUIPMENT_TYPES | SOLD_DATES :--------- | :------------------------ | :------------- 考文垂 |流浪者,流浪者 | 10:00:12,10:00:45 利明顿 |流浪者,Trans Am,Trans Am | 13:10:13,13:10:25,13:10:48 利明顿 | Trans Am,流浪者,护卫舰 | 08:59:45,09:00:00,09:00:10

db小提琴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;

输出:

位置 | EQUIPMENT_TYPES | SOLD_TIMES :--------- | :---------------------------- | :------------------------------------ 考文垂 |流浪者,流浪者,流浪者,流浪者 | 10:00:12,10:00:45,10:01:15,10:01:30 利明顿 |流浪者,Trans Am,Trans Am | 13:10:13,13:10:25,13:10:48 利明顿 | Trans Am,流浪者,护卫舰 | 08:59:45,09:00:00,09:00:10

db小提琴here

【讨论】:

  • MTO:哇,你有!我非常非常感动。谢谢,我考虑过 LAG,但无法让它发挥作用。
  • 如果我们有时间值10:01:13 也是 2019 年 9 月 7 日,如何分组? (尽管如此,这是一个很好的解决方案)
  • @BarbarosÖzhan 小于一分钟的连续时间间隔将包含在同一组中;因此,您可能会发现组中的最小值和最大值之间的间隔大于一分钟,但总会有小于一分钟的时间间隔链。 OP 需要选择它们的组合方式,但几乎不可能有所有值都在一分钟内的组,并且在不引入重复项的情况下不从组中排除其他潜在值,以便一个值可以在多个组中。
  • 此外,您甚至没有证明这不仅仅是“更短”的版本,而是具有不同结果的不同算法
  • 结果不同,因为第一个只有 OP 的数据,而第二个具有相同的数据,除了原始数据之外,还添加了 2 行(在 OP 问题的 cmets 中讨论过)和更新的算法是一样的。
【解决方案2】:

我还没有得到答案,例如,应该如何聚合一连串的多行,其中每一行都比前一行早不到一分钟,例如

  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 分钟,但它们仍然在同一个组中),我将展示如何获取第一次和最后一次销售之间的最大差异

在这种情况下,最好使用带有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 的行,即具有相邻

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

所以我们现在唯一需要的是通过非重叠间隔

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 返回 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

【讨论】:

  • 再次返回,抱歉耽搁了。如果我想通过使用纪元时间来确保销售日期彼此在 1 分钟内,我会怎么做?将 sale_date 转换为 epoch 时间,选择 epoch sale_date 在 1 分钟内的记录
【解决方案3】:

您可以使用LISTAGG(equipment_type,',') WITHIN GROUP (ORDER BY &lt;sold_date_to_minute_precision&gt;) 以及将其他(非聚合)列添加到 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')

Demo

【讨论】:

  • 谢谢巴巴罗斯,我能够在 sqldeveloper 中得到相同的结果。我没有得到漫游者,你得到的漫游者结果
  • 不客气@Gilly,您是否在演示中使用标准日期时间格式检查了 to_timestamp 的转换?
  • Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
  • 我得到的错误是:ORA-01858:在需要数字的地方发现了一个非数字字符
  • 我明白了,所以坚持分钟应该会得到所需的结果。谢谢巴巴罗斯。
【解决方案4】:

在 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;

【讨论】:

  • 这不会找到在00:00:5800:01:02 出售的值。
  • 谢谢 EJ,我使用了以下代码:SELECT location, TO_CHAR (TRUNC (sold_date, 'MI'), 'DD-MON-YYYY HH:MI PM') AS sold_minute, LISTAGG (equipment_type , ',') 组内(按位置排序)作为设备列表 FROM car_sales GROUP BY 位置,TRUNC (sold_date, 'MI') HAVING COUNT (*) > 1;
  • MTO:如何更改代码以允许 00:00:58 和 00:01:02 作为可能的结果?基本上,最好改为 60 秒。但是你是怎么做到的呢?
  • @Gilly - 实际的 car_sales 表是否有主键?有可能,但不能没有表上的主键来防止记录被计算两次。
猜你喜欢
  • 2022-01-24
  • 2019-08-27
  • 2021-04-27
  • 1970-01-01
  • 1970-01-01
  • 2016-11-29
  • 1970-01-01
  • 1970-01-01
  • 2017-03-02
相关资源
最近更新 更多