如何 select 每个组的前 5 个日期并将它们放在 Oracle 中用逗号分隔的单个列中?

How to select the first 5 dates from each group and put them in a single column separated by comma in Oracle?

我有一个 table 这样的:

Division Region Date of Last Visit
1 2 11/20/2021
1 2 11/18/2021
1 7 10/18/2021
1 7 11/19/2021
2 2 11/17/2021
2 3 09/20/2021
2 3 10/20/2021

我想编写一个按部门和地区列分组的查询,并在单个列中为我提供每个组的最后 5 个日期,用逗号分隔。像这样:

Division Region Date of Last Visit Today Days since last visit
1 2 11/20/2021, 11/18/2021 sysdate sysdate - max(date of last visit)
1 7 10/18/2021, 11/19/2021 sysdate sysdate - max(date of last visit)
2 2 11/17/2021 sysdate sysdate - max(date of last visit)
2 3 9/20/2021, 10/20/2021 sysdate sysdate - max(date of last visit)

最后两列是自定义计算列,我也需要它们作为最终输出 table。任何帮助将不胜感激,因为我已经尝试了很多事情,但我不断收到关于它没有正确分组的错误,可能是因为最后有两个额外的列。但即使没有它,我也不确定如何在 oracle 中只获取每组的最后 5 个日期。

谢谢!

给你;阅读代码中的注释。

SQL> with test (division, region, datum) as
  2    -- sample data
  3    (select 1, 2, date '2021-11-20' from dual union all
  4     select 1, 2, date '2021-11-18' from dual union all
  5     select 1, 7, date '2021-10-18' from dual union all
  6     select 1, 7, date '2021-11-19' from dual union all
  7     select 2, 2, date '2021-11-17' from dual union all
  8     select 2, 3, date '2021-09-20' from dual union all
  9     select 2, 3, date '2021-10-20' from dual
 10    ),

 11  temp as
 12    -- rank rows per division/region, sorted by date column in descending order
 13    (select t.*,
 14       rank() over (partition by division, region order by datum desc) rnk
 15     from test t
 16    )
 17  -- select up to 5 last rows per division/region
 18  select division, region,
 19    listagg(datum, ', ') within group (order by datum) dates,
 20    trunc(sysdate) today,
 21    --
 22    (select trunc(sysdate) - a.datum
 23     from temp a
 24     where a.division = t.division
 25       and a.region = t.region
 26       and a.rnk = 1) days_since
 27  from temp t
 28  where rnk <= 5
 29  group by division, region
 30  order by division, region;

  DIVISION     REGION DATES                          TODAY      DAYS_SINCE
---------- ---------- ------------------------------ ---------- ----------
         1          2 11/18/2021, 11/20/2021         11/30/2021         10
         1          7 10/18/2021, 11/19/2021         11/30/2021         11
         2          2 11/17/2021                     11/30/2021         13
         2          3 09/20/2021, 10/20/2021         11/30/2021         41

SQL>

您想使用 ROW_NUMBER 分析函数过滤最大的每组 n,然后聚合:

SELECT division,
       region,
       LISTAGG(TO_CHAR(date_of_last_visit, 'DD/MM/YYYY'), ',')
         WITHIN GROUP (ORDER BY date_of_last_visit DESC)
         AS date_of_last_visit,
       SYSDATE AS today,
       TRUNC(SYSDATE - MAX(date_of_last_visit)) AS days_since_last_visit
FROM   (
  SELECT t.*,
         ROW_NUMBER() OVER (PARTITION BY division, region
                            ORDER BY date_of_last_visit DESC) AS rn
  FROM   table_name t
)
WHERE  rn <= 5
GROUP BY
       division,
       region

其中,对于示例数据:

CREATE TABLE table_name (division, region, date_of_last_visit) as
select 1, 2, date '2021-11-20' from dual union all
select 1, 2, date '2021-11-18' from dual union all
select 1, 7, date '2021-10-18' from dual union all
select 1, 7, date '2021-11-19' from dual union all
select 2, 2, date '2021-11-17' from dual union all
select 2, 3, date '2021-09-20' from dual union all
select 2, 3, date '2021-10-20' from dual;

输出:

DIVISION REGION DATE_OF_LAST_VISIT TODAY DAYS_SINCE_LAST_VISIT
1 2 20/11/2021,18/11/2021 30-NOV-21 10
1 7 19/11/2021,18/10/2021 30-NOV-21 11
2 2 17/11/2021 30-NOV-21 13
2 3 20/10/2021,20/09/2021 30-NOV-21 41

db<>fiddle here