【问题标题】:SELECT for 2 columns from different status选择来自不同状态的 2 列
【发布时间】:2021-12-27 00:53:11
【问题描述】:

我想从两个状态中选择 2 列

ORDER_NUMBER | STATUS   | DATE
--------+-----------+--------------
001          | submit   | 2021-08-31 
113          | submit   | 2021-09-01
113          | approve  | 2021-09-03
001          | cancel   | 2021-09-02
112          | submit   | 2021-09-01
112          | cancel   | 2021-09-10
112          | resubmit | 2021-09-13
112          | approve  | 2021-09-15

预期结果:

ORDER_NUMBER | APPROVE_DATE | CANCEL_DATE
-------------+--------------+--------------
001          | null         | 2021-09-02
112          | 2021-09-15   | 2021-09-10
113          | 2021-09-03   | null 

我的代码:

SELECT ORDER_NUMBER,
    CASE WHEN STATUS = 'approve' THEN DATE END AS APPROVE_DATE,
    CASE WHEN STATUS = 'cancel' THEN DATE END AS CANCEL_DATE
FROM 
    TABLE

但它显示的结果

ORDER_NUMBER | APPROVE_DATE | CANCEL_DATE
-------------+--------------+--------------
001          | null         | null
001          | null         | 2021-09-02
112          | null         | null
112          | null         | 2021-09-10
112          | null         | null
112          | 2021-09-15   | null
113          | null         | null 
113          | 2021-09-03   | null 

显示重复的 ORDER NUMBER 没有我的目标状态,我该如何解决?

【问题讨论】:

  • 请标记正确的dbms
  • 为什么选择这些对?例如,您在取消日期 2021-09-04 旁边显示批准日期 2021-08-31。为什么?它们有某种关联吗?在 SQL 中,您在一行中显示属于一起的数据。我看不出特定的批准和取消日期对是如何相关的。
  • 你需要解释你的逻辑

标签: sql select


【解决方案1】:

您在这里面临的主要问题是第一个表中的不同条目之间绝对没有任何联系:您无法分辨给定的 cancel 条目对应于哪个 approve 条目。

如果您真正想要的是在保留时间顺序的同时将条目分类到右列,您首先需要根据此顺序对表进行排序,然后在另一列中指定 NULL:

SELECT 
    CASE WHEN STATUS = 'approve' THEN DATE ELSE NULL END AS APPROVE_DATE,
    CASE WHEN STATUS = 'cancel' THEN DATE ELSE NULL END AS CANCEL_DATE
FROM 
    TABLE
ORDER BY
    DATE ASC

...这会给你:

APPROVE CANCEL
2021-08-31 NULL
2021-09-03 NULL
NULL 2021-09-04
NULL 2021-09-06
2021-09-09 NULL
NULL 2021-09-20

另外,DATE 是保留关键字,因此您最好为您的列选择另一个名称。这将为您节省以后的麻烦。 ;-)

【讨论】:

  • 谢谢你的回答,我已经编辑了我的信息你能再帮我一次吗?
【解决方案2】:

现在您已经编辑了您的问题,您现在有了一个“订单号”,它是您在表中存储属性的每个实体的实际 ID。

因此,您现在要做的是首先选择所有这些数字,然后为每个数字选择“批准”和“取消”日期。您通常希望使用“joins”来做到这一点。这里的诀窍在于,您完全可以针对同一张表执行自联接。所以像下面这样的事情会做:

SELECT DISTINCT
    t1.order_number,
    t2.status AS Approval_Date,
    […] AS Cancel_Date

FROM table t1

LEFT OUTER JOIN table t2
ON t2.order_number = t1.order_number
AND t2.status = 'approve'

[…]

ORDER BY
    order_number ASC

由于这可能是一个家庭作业,我会让你自己完成这个查询。您只需要像这里描述的那样添加另一个“LEFT OUTER JOIN”块,并为“Cancel_Date”行完成 SELECT 语句。 ;-)

【讨论】:

    【解决方案3】:

    必须在某处有一个 ID 才能将批准与取消相匹配?下面的逻辑将显示批准日期,然后是下一个最早的取消。所以与你的第二行不匹配,但你明白了。

          select a.date Approve_date,
          c.Date Cancel_date
          from Status a
          left join Status c
          on c.order_number = a.order_number
          and c.status = 'cancel'
          where a.status = 'approve'
          order by  a.date
    

    【讨论】:

    • 谢谢你的回答,我已经编辑了我的信息你能再帮我一次吗?
    • @Karina 查看编辑
    【解决方案4】:

    您已更新您的请求。现在您只需选择表格中的所有订单并为每个订单显示批准和取消日期。实现这一点的直接方法是聚合每个订单并在流程中获取名称。根据条件聚合值称为条件聚合。

    您自己的查询非常接近。如果您查看结果,您会发现这只是一个需要按订单 ID 分组的中间结果。您可以通过应用MINMAX 来获取日期。

    SELECT
      order_number,
      MAX(CASE WHEN status = 'approve' THEN date END) AS approve_date,
      MAX(CASE WHEN status = 'cancel' THEN date END) AS cancel_date
    FROM mytable
    GROUP BY order_number
    ORDER BY order_number;
    

    【讨论】:

      猜你喜欢
      • 2017-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-30
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 2018-01-02
      相关资源
      最近更新 更多