获取每月都有订单的客户 – Oracle SQL

huangapple go评论84阅读模式
英文:

Get customers that have ordered consistently each month - Oracle SQL

问题

我正在尝试提取在给定期间内每个月都下订单的客户。我试图包括所有客户,直到他们停止下订单。连续

我已经在下面的表格中创建了我要提取的结果。

客户 日期 状态 新状态
CUST001 Jul-22 首次订单 首次订单
CUST001 Aug-22 连续订单 连续订单
CUST001 Sep-22 连续订单 连续订单
CUST001 Oct-22 停止订单 停止订单
CUST001 Nov-22 N/A 停止订单
CUST001 Dec-22 N/A 停止订单
CUST001 Jan-23 N/A 停止订单
CUST001 Feb-23 N/A 停止订单
CUST001 Mar-23 重新激活 停止订单
CUST001 Apr-23 连续订单 停止订单
CUST001 May-23 停止订单 停止订单

我有一个查询,为每个客户分配自他们的首次订单以来的连续“日期”,并根据他们的订单活动分配状态,基本上是上表中的前三列。我正在尝试编写一个脚本来获取新的状态列,该列应与状态相同,直到状态=“停止订单”,从那时起,它应始终是“停止订单”。

我尝试使用递归CTE(如下所示),使用LAG函数,但它不起作用。它只返回前一个状态作为新状态。

STOPPED_ORDER_ (CUSTOMER, DATE, STATUS, NEW_STATUS, COUNT_) AS
(
SELECT
CUSTOMER,
DATE,
STATUS,
LAG(STATUS) OVER (PARTITION BY CUSTOMER ORDER BY DATE) NEW_STATUS,
1 AS COUNT_
FROM ORDER_STATUS *-- order_status is another cte which assigns status and date *
UNION ALL
SELECT
CUSTOMER,
DATE,
CASE
  WHEN NEW_STATUS = 'STOPPED ORDER' THEN 'STOPPED ORDER' 
    ELSE STATUS END STATUS,
NEW_STATUS,
COUNT_ + 1
FROM STOPPED_ORDER_
WHERE COUNT_ < 1
)

我尝试了不同版本的以下代码,但它不起作用。它始终返回以下结果。

客户 日期 状态 新状态 COUNT_
CUST001 Jul-22 首次订单 1
CUST001 Aug-22 连续订单 首次订单 1
CUST001 Sep-22 连续订单 连续订单 1
CUST001 Oct-22 停止订单 连续订单 1
CUST001 Nov-22 N/A 停止订单 1
CUST001 Dec-22 N/A N/A 1
CUST001 Jan-23 N/A N/A 1
CUST001 Feb-23 N/A N/A 1
CUST001 Mar-23 重新激活 N/A 1
CUST001 Apr-23 连续订单 重新激活 1
CUST001 May-23 停止订单 连续订单 1
英文:

I'm trying to extract customers which have placed orders each month in a given period. I'm trying to include all customers up to the point they stop placing an order. continuous

I've created the result that I'm trying to extract, in the table below.

Customer DATE STATUS NEW STATUS
CUST001 Jul-22 First Order First Order
CUST001 Aug-22 Continuous Order Continuous Order
CUST001 Sep-22 Continuous Order Continuous Order
CUST001 Oct-22 Stopped Order Stopped Order
CUST001 Nov-22 N/A Stopped Order
CUST001 Dec-22 N/A Stopped Order
CUST001 Jan-23 N/A Stopped Order
CUST001 Feb-23 N/A Stopped Order
CUST001 Mar-23 Reactivated Stopped Order
CUST001 Apr-23 Continuous Order Stopped Order
CUST001 May-23 Stopped Order Stopped Order

I have an query which assigns each customer a sequential "DATE" since their first order and assigns status based on their order activity, essentially the first three columns in the above table. I'm trying to write a script to get the New Status column which would be the same as status up to the point where status = 'Stopped Order" and from that point onward, it should always be Stopped Order.

I've tried to use a recursive CTE (copied below) using LAG function, but it doesn't work. It just returns the previous status as the new status.

STOPPED_ORDER_ (CUSTOMER, DATE, STATUS, NEW_STATUS, COUNT_) AS
(
SELECT
CUSTOMER,
DATE,
STATUS,
LAG(STATUS) OVER (PARTITION BY CUSTOMER ORDER BY DATE) NEW_STATUS,
1 AS COUNT_
FROM ORDER_STATUS *-- order_status is another cte which assigns status and date *
UNION ALL
SELECT
CUSTOMER,
DATE,
CASE
  WHEN NEW_STATUS = &#39;STOPPED ORDER&#39; THEN &#39;STOPPED ORDER&#39; 
    ELSE STATUS END STATUS,
NEW_STATUS,
COUNT_ + 1
FROM STOPPED_ORDER_
WHERE COUNT_ &lt; 1
)

I've tried different iterations of the following code but it doesn't work. It always returns the following result

Customer DATE STATUS NEW STATUS COUNT_
CUST001 Jul-22 First Order 1
CUST001 Aug-22 Continuous Order First Order 1
CUST001 Sep-22 Continuous Order Continuous Order 1
CUST001 Oct-22 Stopped Order Continuous Order 1
CUST001 Nov-22 N/A Stopped Order 1
CUST001 Dec-22 N/A N/A 1
CUST001 Jan-23 N/A N/A 1
CUST001 Feb-23 N/A N/A 1
CUST001 Mar-23 Reactivated N/A 1
CUST001 Apr-23 Continuous Order Reactivated 1
CUST001 May-23 Stopped Order Continuous Order 1

答案1

得分: 1

您可以通过使用first_value分析函数来实现这一点,如下所示:

WITH your_results (Customer, order_date, STATUS)
  AS (SELECT 'CUST001',   DATE '2022-07-01',  'First Order' FROM DUAL UNION ALL
      SELECT 'CUST001',   DATE '2022-08-01',  'Continuous Order' FROM DUAL UNION ALL
      SELECT 'CUST001',   DATE '2022-09-01',  'Continuous Order' FROM DUAL UNION ALL
      SELECT 'CUST001',   DATE '2022-10-01',  'Stopped Order' FROM DUAL UNION ALL
      SELECT 'CUST001',   DATE '2022-11-01',  'N/A' FROM DUAL UNION ALL
      SELECT 'CUST001',   DATE '2022-12-01',  'N/A' FROM DUAL UNION ALL
      SELECT 'CUST001',   DATE '2023-01-01',  'N/A' FROM DUAL UNION ALL
      SELECT 'CUST001',   DATE '2023-02-01',  'N/A' FROM DUAL UNION ALL
      SELECT 'CUST001',   DATE '2023-03-01',  'Reactivated' FROM DUAL UNION ALL
      SELECT 'CUST001',   DATE '2023-04-01',  'Continuous Order' FROM DUAL UNION ALL
      SELECT 'CUST001',   DATE '2023-05-01',  'Stopped Order' FROM DUAL)
SELECT customer,
       order_date,
       status,
       NVL(first_value(CASE WHEN status = 'Stopped Order' THEN status END IGNORE NULLS) over (PARTITION BY customer order BY order_date), status) new_status
FROM   your_results;

CUSTOMER ORDER_DATE STATUS NEW_STATUS


CUST001 01/07/2022 First Order First Order
CUST001 01/08/2022 Continuous Order Continuous Order
CUST001 01/09/2022 Continuous Order Continuous Order
CUST001 01/10/2022 Stopped Order Stopped Order
CUST001 01/11/2022 N/A Stopped Order
CUST001 01/12/2022 N/A Stopped Order
CUST001 01/01/2023 N/A Stopped Order
CUST001 01/02/2023 N/A Stopped Order
CUST001 01/03/2023 Reactivated Stopped Order
CUST001 01/04/2023 Continuous Order Stopped Order
CUST001 01/05/2023 Stopped Order Stopped Order

英文:

You can achieve this by using the first_value analytic function, like so:

WITH your_results (Customer, order_date, STATUS)
  AS (SELECT &#39;CUST001&#39;,   DATE &#39;2022-07-01&#39;,  &#39;First Order&#39; FROM DUAL UNION ALL
      SELECT &#39;CUST001&#39;,   DATE &#39;2022-08-01&#39;,  &#39;Continuous Order&#39; FROM DUAL UNION ALL
      SELECT &#39;CUST001&#39;,   DATE &#39;2022-09-01&#39;,  &#39;Continuous Order&#39; FROM DUAL UNION ALL
      SELECT &#39;CUST001&#39;,   DATE &#39;2022-10-01&#39;,  &#39;Stopped Order&#39; FROM DUAL UNION ALL
      SELECT &#39;CUST001&#39;,   DATE &#39;2022-11-01&#39;,  &#39;N/A&#39; FROM DUAL UNION ALL
      SELECT &#39;CUST001&#39;,   DATE &#39;2022-12-01&#39;,  &#39;N/A&#39; FROM DUAL UNION ALL
      SELECT &#39;CUST001&#39;,   DATE &#39;2023-01-01&#39;,  &#39;N/A&#39; FROM DUAL UNION ALL
      SELECT &#39;CUST001&#39;,   DATE &#39;2023-02-01&#39;,  &#39;N/A&#39; FROM DUAL UNION ALL
      SELECT &#39;CUST001&#39;,   DATE &#39;2023-03-01&#39;,  &#39;Reactivated&#39; FROM DUAL UNION ALL
      SELECT &#39;CUST001&#39;,   DATE &#39;2023-04-01&#39;,  &#39;Continuous Order&#39; FROM DUAL UNION ALL
      SELECT &#39;CUST001&#39;,   DATE &#39;2023-05-01&#39;,  &#39;Stopped Order&#39; FROM DUAL)
SELECT customer,
       order_date,
       status,
       NVL(first_value(CASE WHEN status = &#39;Stopped Order&#39; THEN status END IGNORE NULLS) over (PARTITION BY customer order BY order_date), status) new_status
FROM   your_results;

CUSTOMER ORDER_DATE  STATUS           NEW_STATUS
-------- ----------- ---------------- ----------------
CUST001  01/07/2022  First Order      First Order
CUST001  01/08/2022  Continuous Order Continuous Order
CUST001  01/09/2022  Continuous Order Continuous Order
CUST001  01/10/2022  Stopped Order    Stopped Order
CUST001  01/11/2022  N/A              Stopped Order
CUST001  01/12/2022  N/A              Stopped Order
CUST001  01/01/2023  N/A              Stopped Order
CUST001  01/02/2023  N/A              Stopped Order
CUST001  01/03/2023  Reactivated      Stopped Order
CUST001  01/04/2023  Continuous Order Stopped Order
CUST001  01/05/2023  Stopped Order    Stopped Order

答案2

得分: 0

您可以使用 MATCH_RECOGNIZE 进行逐行模式匹配:

SELECT customer,
       order_date,
       status,
       CASE cls
       WHEN &#39;AFTER_STOP&#39; THEN &#39;Stopped Order&#39;
       ELSE status
       END AS new_status
FROM   order_status
MATCH_RECOGNIZE(
  PARTITION BY customer
  ORDER BY order_date
  MEASURES
    classifier() AS cls
  ALL ROWS PER MATCH
  PATTERN ( first_order any_order* (stopped_order after_stop*)? )
  DEFINE
    first_order   AS  status = &#39;First Order&#39;,
    any_order     AS  status != &#39;Stopped Order&#39;
                  AND ADD_MONTHS(PREV(order_date), 1) = order_date,
    stopped_order AS  status = &#39;Stopped Order&#39;
                  AND ADD_MONTHS(PREV(order_date), 1) = order_date,
    after_stop    AS  ADD_MONTHS(PREV(order_date), 1) = order_date
);

对于示例数据:

CREATE TABLE ORDER_STATUS (Customer, order_date, STATUS) AS
SELECT &#39;CUST001&#39;,	DATE &#39;2022-07-01&#39;,	&#39;First Order&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2022-08-01&#39;,	&#39;Continuous Order&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2022-09-01&#39;,	&#39;Continuous Order&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2022-10-01&#39;,	&#39;Stopped Order&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2022-11-01&#39;,	&#39;N/A&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2022-12-01&#39;,	&#39;N/A&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2023-01-01&#39;,	&#39;N/A&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2023-02-01&#39;,	&#39;N/A&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2023-03-01&#39;,	&#39;Reactivated&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2023-04-01&#39;,	&#39;Continuous Order&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2023-05-01&#39;,	&#39;Stopped Order&#39; FROM DUAL;

输出:

CUSTOMER ORDER_DATE STATUS NEW_STATUS
CUST001 2022-07-01 00:00:00 First Order First Order
CUST001 2022-08-01 00:00:00 Continuous Order Continuous Order
CUST001 2022-09-01 00:00:00 Continuous Order Continuous Order
CUST001 2022-10-01 00:00:00 Stopped Order Stopped Order
CUST001 2022-11-01 00:00:00 N/A Stopped Order
CUST001 2022-12-01 00:00:00 N/A Stopped Order
CUST001 2023-01-01 00:00:00 N/A Stopped Order
CUST001 2023-02-01 00:00:00 N/A Stopped Order
CUST001 2023-03-01 00:00:00 Reactivated Stopped Order
CUST001 2023-04-01 00:00:00 Continuous Order Stopped Order
CUST001 2023-05-01 00:00:00 Stopped Order Stopped Order

fiddle

英文:

You can use MATCH_RECOGNIZE to perform row-by-row pattern matching:

SELECT customer,
       order_date,
       status,
       CASE cls
       WHEN &#39;AFTER_STOP&#39; THEN &#39;Stopped Order&#39;
       ELSE status
       END AS new_status
FROM   order_status
MATCH_RECOGNIZE(
  PARTITION BY customer
  ORDER BY order_date
  MEASURES
    classifier() AS cls
  ALL ROWS PER MATCH
  PATTERN ( first_order any_order* (stopped_order after_stop*)? )
  DEFINE
    first_order   AS  status = &#39;First Order&#39;,
    any_order     AS  status != &#39;Stopped Order&#39;
                  AND ADD_MONTHS(PREV(order_date), 1) = order_date,
    stopped_order AS  status = &#39;Stopped Order&#39;
                  AND ADD_MONTHS(PREV(order_date), 1) = order_date,
    after_stop    AS  ADD_MONTHS(PREV(order_date), 1) = order_date
);

Which, for the sample data:

CREATE TABLE ORDER_STATUS (Customer, order_date, STATUS) AS
SELECT &#39;CUST001&#39;,	DATE &#39;2022-07-01&#39;,	&#39;First Order&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2022-08-01&#39;,	&#39;Continuous Order&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2022-09-01&#39;,	&#39;Continuous Order&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2022-10-01&#39;,	&#39;Stopped Order&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2022-11-01&#39;,	&#39;N/A&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2022-12-01&#39;,	&#39;N/A&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2023-01-01&#39;,	&#39;N/A&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2023-02-01&#39;,	&#39;N/A&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2023-03-01&#39;,	&#39;Reactivated&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2023-04-01&#39;,	&#39;Continuous Order&#39; FROM DUAL UNION ALL
SELECT &#39;CUST001&#39;,	DATE &#39;2023-05-01&#39;,	&#39;Stopped Order&#39; FROM DUAL;

Outputs:

CUSTOMER ORDER_DATE STATUS NEW_STATUS
CUST001 2022-07-01 00:00:00 First Order First Order
CUST001 2022-08-01 00:00:00 Continuous Order Continuous Order
CUST001 2022-09-01 00:00:00 Continuous Order Continuous Order
CUST001 2022-10-01 00:00:00 Stopped Order Stopped Order
CUST001 2022-11-01 00:00:00 N/A Stopped Order
CUST001 2022-12-01 00:00:00 N/A Stopped Order
CUST001 2023-01-01 00:00:00 N/A Stopped Order
CUST001 2023-02-01 00:00:00 N/A Stopped Order
CUST001 2023-03-01 00:00:00 Reactivated Stopped Order
CUST001 2023-04-01 00:00:00 Continuous Order Stopped Order
CUST001 2023-05-01 00:00:00 Stopped Order Stopped Order

fiddle

huangapple
  • 本文由 发表于 2023年6月22日 16:00:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76529723.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定