【问题标题】:How to return next status following a specific status that has occured如何在发生的特定状态之后返回下一个状态
【发布时间】:2021-11-09 02:23:14
【问题描述】:

我希望在收到订单后返回下一个状态,但只希望捕获以下列表中的某些状态:“已发货”、“部分发货”、“已取消” 下面是订单表

Order ID Order Status Date
1 Received 1/1/2021
1 Partially Shipped 1/1/2021
1 Returned 1/2/2021
1 Received 1/2/2021
1 Shipped 1/3/2021
2 Received 1/1/2021
2 Acknowledged 1/1/2021
2 Shipped 1/1/2021

如您所见,订单 ID 2 收到后的以下状态为已确认,但我只想获取以下列表中的下一个状态:“已发货”、“部分发货”、“已取消” 因此,以下输出将是正确的,跳过确认并返回已发货

Order ID Order Status Date
1 Partially Shipped 1/1/2021
1 Shipped 1/3/2021
2 Shipped 1/1/2021

【问题讨论】:

  • 请不要张贴桌子的照片。只需将其显示为文本。您将需要查看 oracle 窗口/分析函数。
  • 你能告诉我们你的尝试吗?

标签: sql oracle


【解决方案1】:

您可以使用带有IGNORE NULLS 子句的条件LAG 分析语句:

SELECT Order_id,
       Order_status,
       "DATE"
FROM   (
  SELECT t.*,
         LAG(
           CASE
           WHEN order_status IN ('Received', 'Shipped', 'Partially Shipped', 'Cancelled')
           THEN order_status
           END
         ) IGNORE NULLS OVER (PARTITION BY order_id ORDER BY "DATE") AS prev_status
  FROM   table_name t
)
WHERE  prev_status = 'Received'
AND    order_status IN ('Shipped', 'Partially Shipped', 'Cancelled')

其中,对于样本数据:

CREATE TABLE table_name (Order_ID, Order_Status, "DATE") AS
SELECT 1, 'Received',          DATE '2021-01-01' FROM DUAL UNION ALL
SELECT 1, 'Partially Shipped', DATE '2021-01-01' FROM DUAL UNION ALL
SELECT 1, 'Shipped',           DATE '2021-01-02' FROM DUAL UNION ALL
SELECT 1, 'Returned',          DATE '2021-02-01' FROM DUAL UNION ALL
SELECT 1, 'Received',          DATE '2021-02-01' FROM DUAL UNION ALL
SELECT 1, 'Shipped',           DATE '2021-03-01' FROM DUAL UNION ALL
SELECT 2, 'Received',          DATE '2021-01-01' FROM DUAL UNION ALL
SELECT 2, 'Acknowledged',      DATE '2021-01-01' FROM DUAL UNION ALL
SELECT 2, 'Shipped',           DATE '2021-01-01' FROM DUAL UNION ALL
SELECT 3, 'Received',          DATE '2021-01-01' FROM DUAL UNION ALL
SELECT 3, 'Acknowledged',      DATE '2021-02-01' FROM DUAL UNION ALL
SELECT 4, 'Received',          DATE '2021-01-01' FROM DUAL UNION ALL
SELECT 4, 'Acknowledged',      DATE '2021-02-01' FROM DUAL UNION ALL
SELECT 4, 'Received',          DATE '2021-01-01' FROM DUAL;

输出:

ORDER_ID ORDER_STATUS DATE
1 Partially Shipped 2021-01-01 00:00:00
1 Shipped 2021-03-01 00:00:00
2 Shipped 2021-01-01 00:00:00

db小提琴here

【讨论】:

    【解决方案2】:

    您可以使用match_recognize 来处理这里看起来合适的情况,因为它可以处理要包含的状态的重复。它适用于所有受支持的版本(自 12c 起)。

    我添加了额外的行来显示它是如何处理的,例如'Partially Shipped' 之后的'Shipped',以及所需状态列表中缺少下一个状态(如order_id = 3)。

    with a (Order_ID, Order_Status, dt) as (
      select 1, 'Received', date '2021-01-01'           from dual union all
      select 1, 'Partially Shipped', date '2021-01-01'  from dual union all
      select 1, 'Shipped', date '2021-01-02'           from dual union all
      select 1, 'Returned', date '2021-02-01'           from dual union all
      select 1, 'Received', date '2021-02-01'           from dual union all
      select 1, 'Shipped', date '2021-03-01'           from dual union all
      select 2, 'Received', date '2021-01-01'           from dual union all
      select 2, 'Acknowledged', date '2021-01-01'       from dual union all
      select 2, 'Shipped', date '2021-01-01'           from dual union all
      select 3, 'Received', date '2021-01-01'           from dual union all
      select 3, 'Acknowledged', date '2021-02-01'       from dual union all
      select 3, 'Received', date '2021-03-01'           from dual union all
      select 4, 'Received', date '2021-01-01'           from dual union all
      select 4, 'Acknowledged', date '2021-02-01'       from dual union all
      select 4, 'Received', date '2021-03-01'           from dual union all
      select 4, 'Acknowledged', date '2021-03-02'       from dual union all
      select 4, 'Shipped', date '2021-03-05'       from dual
    )
    select *
    from a
    match_recognize (
      partition by order_id
      order by dt asc
      all rows per match
      /*Return the next status after 'Received', that is in a list of interest*/
      pattern (
        {- received -} /*Exclude 'Received' from output*/
        {- exclude* -} /*Exclude "other" statuses after 'Received'*/
        next? /*And include the next status that should be in the list.
                Marked as optional to allow previous exclusion group
                to catch not listed statuses*/
      )
      define
        received as order_status = 'Received',
        /*Other statuses (that are out of interest)*/
        exclude as order_status not in ('Shipped', 'Partially Shipped', 'Cancelled'),
        /*To break match if the next status is not from the list*/
        next as order_status in ('Shipped', 'Partially Shipped', 'Cancelled')
    )
    
    ORDER_ID | DT |订单状态 --------: | :--------- | :----------- 1 | 2021-01-02 |已发货 1 | 2021-03-01 |已发货 2 | 2021-01-01 |已发货 4 | 2021-03-05 |已发货

    db小提琴here

    【讨论】:

    • 是否需要定义next AS order_status not in ('Shipped', 'Partially Shipped', 'Cancelled'),否则会发现“下一个”状态返回为“已接收”?
    • 我不应该在我之前的评论中包含“不”;那是我的复制粘贴错误。很抱歉有任何混淆。
    • @MT0 谢谢!我也在排除列表之后添加了这个带有Received 的测试用例。我认为next 应该只是一个所需状态的列表,因为我们需要它们而不是'Received'(它更冗长)。还重新组织了exclude 模式,因为如果'Received' 将被捕获,那么到目前为止还没有满足列表中的任何状态,所以匹配应该跨越更多行,直到它达到next 模式。我已经删除了我之前的误导性评论。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-24
    • 2012-02-12
    • 2019-01-09
    • 1970-01-01
    相关资源
    最近更新 更多