Match_recognize 并加入 ORA-00918

问题描述 投票:0回答:1

这是我几天前提出的一个问题的后续,所以我提前为开始一个新问题(如果礼仪不妥)表示歉意。 我正在尝试使用 March_recognize 为连续 10 天以上购买的客户提供资金。下面的查询正在运行,并给出了我想要的结果。

我尝试使用 JOIN 修改查询以在输出中显示客户的名字和姓氏,但没有成功并收到以下错误,我似乎无法解决该错误。我希望有人能告诉我如何解决这个问题。感谢所有回复的人。 ORA-00918: 列定义不明确


ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'DD-MON-YYYY  HH24:MI:SS.FF';
CREATE TABLE customers 
(CUSTOMER_ID, FIRST_NAME, LAST_NAME) AS
SELECT 1, 'John', 'Doe' FROM DUAL UNION ALL
SELECT 2, 'Ann', 'Smith' FROM DUAL UNION ALL
SELECT 3, 'Mike', 'Jones' FROM DUAL;


create table purchases(
  ORDER_ID NUMBER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
  customer_id   number, 
  PRODUCT_ID NUMBER, 
  QUANTITY NUMBER, 
  purchase_date timestamp
);

insert  into purchases (customer_id, product_id, quantity, purchase_date)
    select  1 customer_id, 101 product_id, 1 quantity,
             DATE '2024-04-08' + INTERVAL '13' HOUR + ((LEVEL-1) * INTERVAL '1 00:00:01' DAY TO SECOND)  * -1
           as purchase_date
    from    dual
    connect by level <= 15 UNION all
    select  2, 102, 1,
             DATE '2024-03-08' + INTERVAL '14' HOUR + ((LEVEL-1) * INTERVAL '1 00:00:00' DAY TO SECOND) * -1
   from    dual
   connect by level <= 5 UNION ALL 
select  3, 103, 1,
             DATE '2024-02-08' + INTERVAL '15' HOUR + ((LEVEL-1) * INTERVAL '0 23:59:59' DAY TO SECOND) * -1
   from    dual
   connect by level <= 5;

/* current query works fine thanks to Alex Poole */

select customer_id,
            first_date,
            last_date,
          trunc(last_date) - trunc(first_date) + 1 as consecutive_days
from purchases 
match_recognize(
    partition by customer_id
    order by purchase_date
    measures
        first(purchase_date) as first_date,
        last(purchase_date) as last_date
    one row per match
    pattern(start_date P{9,})
    define P as purchase_date >= prev(trunc(purchase_date)) + interval '1' day
      and purchase_date < prev(trunc(purchase_date)) + interval '2' day
);

/* Desired modified output */

CUSTOMER_ID FIRST_NAME LAST_NAME START_DATE END_DATE CONTINUOUS_DAYS
1 John Doe 25-MAR-2024  12:59:46.000000
08-APR-2024  13:00:00.000000 15


/* one of many failed attempts */
select pur customer_id,
           c.first_name,
            c.last_name,
            first_date,
            last_date,
          trunc(last_date) - trunc(first_date) + 1 as consecutive_days
FROM purchases pur LEFT OUTER JOIN customers c ON c.custimer_id = pur.customer_id  
match_recognize(
    partition by pur.customer_id
    order by pur.purchase_date
    measures
        first(purchase_date) as first_date,
        last(purchase_date) as last_date
    one row per match
    pattern(start_date P{9,})
    define P as purchase_date >= prev(trunc(purchase_date)) + interval '1' day
      and purchase_date < prev(trunc(purchase_date)) + interval '2' day
);

oracle join match-recognize
1个回答
1
投票

加入

MATCH_RECOGNIZE
而不是加入
purchases
表:

select m.customer_id,
       c.first_name,
       c.last_name,
       m.first_date,
       m.last_date,
       trunc(m.last_date) - trunc(m.first_date) + 1 as consecutive_days
FROM   purchases pur  
       match_recognize(
         partition by customer_id
         order by purchase_date
         measures
           first(purchase_date) as first_date,
           last(purchase_date) as last_date
         one row per match
         pattern(start_date P{9,})
         define P as
               purchase_date >= prev(trunc(purchase_date)) + interval '1' day
           and purchase_date < prev(trunc(purchase_date)) + interval '2' day
       ) m
       LEFT OUTER JOIN customers c ON c.customer_id = m.customer_id;

对于样本数据,输出:

CUSTOMER_ID FIRST_NAME LAST_NAME FIRST_DATE LAST_DATE CONSECUTIVE_DAYS
1 约翰 母鹿 2024-03-25 12:59:46.000000 2024-04-08 13:00:00.000000 15

您可以之前这样做,但它更尴尬,因为您需要在子查询中连接两个表(并消除列的歧义 - 这就是错误的来源,因为

purchases
customers
都有一个
customer_id 
列),然后使用
MATCH_RECOGNIZE
并确保其他列也被执行:

select m.customer_id,
       m.first_name,
       m.last_name,
       m.first_date,
       m.last_date,
       trunc(m.last_date) - trunc(m.first_date) + 1 as consecutive_days
FROM   (
         SELECT p.*, c.first_name, c.last_name
         FROM   purchases p
                LEFT OUTER JOIN customers c
                ON c.customer_id = p.customer_id
       ) cp
       MATCH_RECOGNIZE(
         PARTITION BY customer_id
         ORDER BY     purchase_date
         MEASURES
           MIN(first_name)      AS first_name,
           MIN(last_name)       AS last_name,
           FIRST(purchase_date) AS first_date,
           LAST(purchase_date)  AS last_date
         ONE ROW PER MATCH
         PATTERN ( consecutive{9,} final_date )
         DEFINE consecutive as
               purchase_date >= NEXT(TRUNC(purchase_date)) - interval '1' day
           AND purchase_date <  NEXT(TRUNC(purchase_date))
       ) m;

小提琴

© www.soinside.com 2019 - 2024. All rights reserved.