【问题标题】:Select first and nth order for each client为每个客户选择第一个和第 n 个订单
【发布时间】:2021-02-23 20:11:19
【问题描述】:

我正在尝试为每个用户显示第一个和第五个 order_id。

表格如下:

+----------+-----------+-------------------+
| Order_ID | Client_ID | Datetime          |
+----------+-----------+-------------------+
| 1        | 1         | YYYYMMDD HH:MM:SS |
+----------+-----------+-------------------+
| 2        | 1         | YYYYMMDD HH:MM:SS |
+----------+-----------+-------------------+
| 3        | 2         | YYYYMMDD HH:MM:SS |
+----------+-----------+-------------------+

我是这样写的:

select 
  t.client_id, 
  t.order_id as first_order, 
  t2.order_id as fifth_order,
  t.datetime as first_dt,
  t2.datetime as fifth_dt,
from
(
  select o.client_id, o.order_id, o.datetime,
  row_number() over(partition by o.client_id order by o.datetime) as rn
  from "OhMyTable" as o
) as t
  left join
    (
  select o.client_id, o.order_id, o.datetime,
  row_number() over(partition by o.client_id order by o.order_id) as rn
  from "OhMyTable" as o
      order by o.order_id
  ) as t2
  on t.client_id = t2.client_id
where t.rn = 1 and t2.rn = 5

但我希望看到那些下了第一单但没有五分之一的客户。应该有NULL,但我不明白怎么做。 :c

【问题讨论】:

    标签: sql postgresql pivot left-join greatest-n-per-group


    【解决方案1】:

    使用条件聚合:

    select o.client_id,
           min(datetime) as first_datetime,
           max(datetime) as fifth_datime,
           max(case when seqnum = 1 then order_id end) as first_orderid,
           max(case when seqnum = 5 then order_id end) as fifth_orderid
    from (select o.*
                 row_number() over(partition by o.client_id order by o.datetime) as seqnum
          from "OhMyTable" o
         ) o
    where seqnum in (1, 5);
    

    【讨论】:

      【解决方案2】:

      如果发现条件聚合比两个子查询更简单。您可以使用having 子句进行过滤:

      select client_id,
          max(order_id) filter(where rn = 1) first_order,
          max(order_id) filter(where rn = 5) fifth_order,
          min(datetime) first_dt,
          max(datetime) fifth_dt
      from (
          select o.client_id, o.order_id, o.datetime,
              row_number() over(partition by o.client_id order by o.datetime) as rn
          from "OhMyTable" as o
      ) t
      where rn in (1, 5)
      group by client_id
      having count(*) = 2
      

      【讨论】:

        【解决方案3】:

        where t2.rn = 5 条件放入left join

        select 
          t.client_id, 
          t.order_id as first_order, 
          t2.order_id as fifth_order,
          t.datetime as first_dt,
          t2.datetime as fifth_dt,
        from
        (
          select o.client_id, o.order_id, o.datetime,
          row_number() over(partition by o.client_id order by o.datetime) as rn
          from "OhMyTable" as o
        ) as t
          left join
            (
          select o.client_id, o.order_id, o.datetime,
          row_number() over(partition by o.client_id order by o.order_id) as rn
          from "OhMyTable" as o
              order by o.order_id
          ) as t2
          on t.client_id = t2.client_id
          and t2.rn = 5
        where t.rn = 1 and t2.datetime is null
        

        【讨论】:

          猜你喜欢
          • 2021-04-09
          • 2011-05-02
          • 1970-01-01
          • 2011-11-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-12-28
          • 2023-03-25
          相关资源
          最近更新 更多