题目描述

(通过次数1,664 | 提交次数2,011,通过率82.74%)

活动表: Orders
+-------------+------+
| Column Name | Type |
+-------------+------+
| order_id    | int  | 
| customer_id | int  |
| order_type  | int  | 
+-------------+------+
order_id是此表的主键列。
此表的每一行都表示订单的ID、订购该订单的客户的ID以及订单类型。
订单可以是类型0或类型1。

编写SQL查询以根据以下条件报告所有订单:
如果客户至少有一个类型为0的订单,则不要报告该客户的任何类型为1的订单。
否则,报告客户的所有订单。
按任意顺序返回结果表。

查询结果格式如下例所示。
示例 1:
输入: 
Orders table:
+----------+-------------+------------+
| order_id | customer_id | order_type |
+----------+-------------+------------+
| 1        | 1           | 0          |
| 2        | 1           | 0          |
| 11       | 2           | 0          |
| 12       | 2           | 1          |
| 21       | 3           | 1          |
| 22       | 3           | 0          |
| 31       | 4           | 1          |
| 32       | 4           | 1          |
+----------+-------------+------------+
输出: 
+----------+-------------+------------+
| order_id | customer_id | order_type |
+----------+-------------+------------+
| 31       | 4           | 1          |
| 32       | 4           | 1          |
| 1        | 1           | 0          |
| 2        | 1           | 0          |
| 11       | 2           | 0          |
| 22       | 3           | 0          |
+----------+-------------+------------+
解释: 
客户1有两个类型为0的订单。我们两个都返回。
客户2的订单类型为0,订单类型为1。我们只返回类型为0的订单。
客户3的订单类型为0,订单类型为1。我们只返回类型为0的订单。
客户4有两个类型1的订单。我们两个都返回。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/drop-type-1-orders-for-customers-with-type-0-orders
//测试数据
Create table If Not Exists Orders (order_id int, customer_id int, order_type int);

insert into Orders (order_id, customer_id, order_type) values ('1', '1', '0');
insert into Orders (order_id, customer_id, order_type) values ('2', '1', '0');
insert into Orders (order_id, customer_id, order_type) values ('11', '2', '0');
insert into Orders (order_id, customer_id, order_type) values ('12', '2', '1');
insert into Orders (order_id, customer_id, order_type) values ('21', '3', '1');
insert into Orders (order_id, customer_id, order_type) values ('22', '3', '0');
insert into Orders (order_id, customer_id, order_type) values ('31', '4', '1');
insert into Orders (order_id, customer_id, order_type) values ('32', '4', '1');

解题思路

Orders表中保存了类型为0和1的所有订单。
题目要求:如果某客户存在类型为0、1的订单,那么仅返回该客户类型为0的订单;
如果某客户仅存在类型为0的订单,那么返回该客户类型为0的订单;
如果某客户仅存在类型为1的订单,那么返回该客户类型为1的订单;
从直观上理解,可以对类型为0和类型为1的订单分别查询。
类型为0的所有订单都需要返回。
类型为1的订单,只有当客户不存在类型为0的订单时才返回。
然后将这两部分结果合并即可。

select
    a.order_id,
    a.customer_id,
    a.order_type
from Orders a
where a.order_type = 0
union all
select
    a.order_id,
    a.customer_id,
    a.order_type
from Orders a
where a.order_type = 1
  and not exists(select 1 from Orders b 
            where a.customer_id = b.customer_id 
            and b.order_type = 0);

除了上面的思路外,也可以从另一个方向思考:
当某客户存在类型为0、1的订单时,只返回类型为0的订单;
当某客户仅存在类型为0的订单时,需要返回;
当某客户仅存在类型为1的订单时,也需要返回;
那么,其实,这也是一个开窗排序的场景,按类型从小到大排序,只取序号为1的订单。
下面的参考SQL即是按这个思路实现的。

参考SQL

未特别说明的情况下,参考SQL为基于MySQL8.0实现。
select
    b.order_id,
    b.customer_id,
    b.order_type
from (
    select
        a.order_id,
        a.customer_id,
        a.order_type,
        rank() over(partition by a.customer_id order by a.order_type) rk
    from Orders a
) b
where b.rk = 1;
picture loss