oracle 提取最近日期之间的所有记录按ID分组

xeufq47z  于 2023-04-29  发布在  Oracle
关注(0)|答案(3)|浏览(259)

假设我有一个像下面这样的表:
| 身份证|起始值|终值|日期|价值|
| --------------|--------------|--------------|--------------|--------------|
| 1|零|零|23年4月5日|二|
| 1|零|五|23年4月9日|零|
| 1|五|零|23年4月15日|零|
| 1|零|零|2023年4月16日|四|
| 1|零|零|2023年4月16日|-1|
| 1|零|八个|2023年4月16日|零|
| 二|1|零|23年4月5日|零|
| 二|零|九|23年4月9日|零|
| 二|九|零|2023年4月13日|零|
| 二|零|零|2023年4月13日|1|
| 二|零|零|23年4月14日|-5|
| 二|零|零|23年4月15日|-3|
| 二|零|零|2023年4月16日|-4个|
| 二|零|-1|2023年4月16日|零|
我问a question before,可以得到最新的非空开始和结束值的id如下与SQL:

SELECT id,
       start_value,
       end_value,
       start_date,
       end_date
FROM   (
  SELECT id,
         LAST_VALUE(start_value)
            IGNORE NULLS OVER (PARTITION BY id ORDER BY "DATE") AS start_value,
         LAST_VALUE(end_value)
            IGNORE NULLS OVER (PARTITION BY id ORDER BY "DATE") AS end_value,
         LAST_VALUE(CASE WHEN start_value IS NOT NULL THEN "DATE" END)
            IGNORE NULLS OVER (PARTITION BY id ORDER BY "DATE") AS start_date,
         LAST_VALUE(CASE WHEN end_value IS NOT NULL THEN "DATE" END)
            IGNORE NULLS OVER (PARTITION BY id ORDER BY "DATE") AS end_date,
         ROW_NUMBER()
            OVER (PARTITION BY id ORDER BY "DATE" DESC) AS rn
  FROM   table_name
)
WHERE  rn = 1
身份证起始值终值开始日期结束日期
1八个23年4月15日2023年4月16日
-12023年4月13日2023年4月16日

现在,我想获得一个ID的最新非空开始和结束日期之间的中间值,如下所示,但不知道如何做到这一点:
| 身份证|起始值|终值|日期|价值|
| --------------|--------------|--------------|--------------|--------------|
| 1|五|零|23年4月15日|零|
| 1|零|零|23年4月15日|四|
| 1|零|零|2023年4月16日|-1|
| 1|零|八个|2023年4月16日|零|
| 二|九|零|2023年4月13日|零|
| 二|零|零|2023年4月13日|1|
| 二|零|零|23年4月14日|-5|
| 二|零|零|23年4月15日|-3|
| 二|零|零|2023年4月16日|-4个|
| 二|零|-1|2023年4月16日|零|

xzabzqsa

xzabzqsa1#

在整个结果集上用一个窗口查找开始和结束日期的LAST_VALUE,然后对其进行过滤:

SELECT id,
       start_value,
       end_value,
       "DATE",
       value
FROM   (
  SELECT t.*,
         LAST_VALUE(CASE WHEN start_value IS NOT NULL THEN "DATE" END)
            IGNORE NULLS OVER (
              PARTITION BY id ORDER BY "DATE"
              ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
            ) AS start_date,
         LAST_VALUE(CASE WHEN end_value IS NOT NULL THEN "DATE" END)
            IGNORE NULLS OVER (
              PARTITION BY id ORDER BY "DATE"
              ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
            ) AS end_date
  FROM   table_name t
)
WHERE  "DATE" BETWEEN start_date AND end_date

其中,对于样本数据:

CREATE TABLE table_name (id, start_value, end_value, "DATE", value) AS
SELECT 1, null, null, DATE '2023-04-05', 2 FROM DUAL UNION ALL
SELECT 1, null, 5,    DATE '2023-04-09', null FROM DUAL UNION ALL
SELECT 1, 5,    null, DATE '2023-04-15', null FROM DUAL UNION ALL
SELECT 1, null, null, DATE '2023-04-16', -4 FROM DUAL UNION ALL
SELECT 1, null, null, DATE '2023-04-16', -1 FROM DUAL UNION ALL
SELECT 1, null, 8,    DATE '2023-04-16', null FROM DUAL UNION ALL
SELECT 2, 1,    null, DATE '2023-04-05', null FROM DUAL UNION ALL
SELECT 2, null, 9,    DATE '2023-04-09', null FROM DUAL UNION ALL
SELECT 2, 9,    null, DATE '2023-04-13', null FROM DUAL UNION ALL
SELECT 2, null, null, DATE '2023-04-13', 1 FROM DUAL UNION ALL
SELECT 2, null, null, DATE '2023-04-14', -5 FROM DUAL UNION ALL
SELECT 2, null, null, DATE '2023-04-15', -3 FROM DUAL UNION ALL
SELECT 2, null, null, DATE '2023-04-16', -4 FROM DUAL UNION ALL
SELECT 2, null, -1,   DATE '2023-04-16', null FROM DUAL;

输出:
| ID|开始值|END_VALUE|日期|价值|
| --------------|--------------|--------------|--------------|--------------|
| 1|五|联系我们|2019 -04-15 00:00:00|联系我们|
| 1|联系我们|联系我们|2019 -04-16 00:00:00|-4个|
| 1|联系我们|联系我们|2019 -04-16 00:00:00|-1|
| 1|联系我们|八个|2019 -04-16 00:00:00|联系我们|
| 二|九|联系我们|2019 -04-13 00:00:00|联系我们|
| 二|联系我们|联系我们|2019 -04-13 00:00:00|1|
| 二|联系我们|联系我们|2019 -04-14 00:00:00|-5|
| 二|联系我们|联系我们|2019 -04-15 00:00:00|-3|
| 二|联系我们|联系我们|2019 -04-16 00:00:00|-4个|
| 二|联系我们|-1|2019 -04-16 00:00:00|联系我们|
fiddle

kxxlusnw

kxxlusnw2#

您可以计算每个id的非空start_value值的数量,然后使用DENSE_RANK对每个id的计数进行排名。一旦你有了,你可以使用rank = 1,就像你以前的文章一样。

WITH cte AS (
    SELECT tab.*, 
           COUNT(start_value) OVER(PARTITION BY id ORDER BY date_) AS cnt
    FROM tab
), cte2 AS (
    SELECT cte.*,
           DENSE_RANK() OVER(PARTITION BY id ORDER BY cnt DESC) AS rn 
    FROM cte
)
SELECT id,
       start_value,
       end_value,
       date_,
       value_
FROM cte2
WHERE rn = 1
ORDER BY id, date_, start_value, value_, end_value

输出

ID开始值END_VALUE日期_价值观_
123年4月15日
12023年4月16日-1
12023年4月16日
1八个2023年4月16日
2023年4月13日
2023年4月13日1
23年4月14日-5
23年4月15日-3
2023年4月16日-4个
-12023年4月16日

检查演示here
如果您不介意输出行的顺序,另一种选择是使用FETCH FIRST 1 ROWS WITH TIES子句。

WITH cte AS (
    SELECT tab.*, 
           COUNT(start_value) OVER(PARTITION BY id ORDER BY date_) AS cnt
    FROM tab
)
SELECT id,
       start_value,
       end_value,
       date_,
       value_
FROM cte
ORDER BY CASE WHEN DENSE_RANK() OVER(PARTITION BY id ORDER BY cnt DESC) = 1 THEN 1 END
FETCH FIRST 1 ROW WITH TIES
jaxagkaj

jaxagkaj3#

可以使用查询来完成,该查询获取cte中最新的非空开始值和结束值,然后将其连接到表中,如下所示:

with cte as (
  SELECT id,
       start_value,
       end_value,
       start_date,
       end_date,
       value
  FROM   (
  SELECT id,
         LAST_VALUE(start_value)
            IGNORE NULLS OVER (PARTITION BY id ORDER BY "DATE") AS start_value,
         LAST_VALUE(end_value)
            IGNORE NULLS OVER (PARTITION BY id ORDER BY "DATE") AS end_value,
         LAST_VALUE(CASE WHEN start_value IS NOT NULL THEN "DATE" END)
            IGNORE NULLS OVER (PARTITION BY id ORDER BY "DATE") AS start_date,
         LAST_VALUE(CASE WHEN end_value IS NOT NULL THEN "DATE" END)
            IGNORE NULLS OVER (PARTITION BY id ORDER BY "DATE") AS end_date,
         ROW_NUMBER()
            OVER (PARTITION BY id ORDER BY "DATE" DESC) AS rn,
        value
  FROM   table_name
  )
  WHERE  rn = 1
)
select t.*
from table_name t
inner join cte c on t.id = c.id and T."DATE" between start_date AND end_date;

结果:
| 身份证|起始值|终值|日期|价值|
| --------------|--------------|--------------|--------------|--------------|
| 1|五|零|23年4月15日|零|
| 1|零|零|23年4月15日|四|
| 1|零|零|2023年4月16日|-1|
| 1|零|八个|2023年4月16日|零|
| 二|九|零|2023年4月13日|零|
| 二|零|零|2023年4月13日|1|
| 二|零|零|23年4月14日|-5|
| 二|零|零|23年4月15日|-3|
| 二|零|零|2023年4月16日|-4个|
| 二|零|-1|2023年4月16日|零|
Demo here

相关问题