Oracle SQL-获取每列的最新值

时间:2020-11-11 09:18:09

标签: sql oracle

假设我有一个像这样的表:

Sample table

表中有2个ISIN(ISIN 1和2)。如果查看第一行,将会看到所有字段都填充了值。在第二行中,仅填充了一个字段,代表该字段的更新(所有空白字段均未更改)。

基本上我想要每个字段的最新值(按ISIN分组)。

Result

我想创建一个物化视图,如果有内置功能或简单的方法来获得结果。如果没有,我将创建管道函数并遍历记录。

3 个答案:

答案 0 :(得分:1)

您可以使用LAST_VALUE分析函数:

SELECT ts,
       id,
       isin,
       value1,
       value2,
       value3,
       value4,
       value5,
       value6
FROM   (
  SELECT ts,
         id,
         isin,
         LAST_VALUE(value1) IGNORE NULLS OVER ( PARTITION BY isin ORDER BY ts, id ) AS value1,
         LAST_VALUE(value2) IGNORE NULLS OVER ( PARTITION BY isin ORDER BY ts, id ) AS value2,
         LAST_VALUE(value3) IGNORE NULLS OVER ( PARTITION BY isin ORDER BY ts, id ) AS value3,
         LAST_VALUE(value4) IGNORE NULLS OVER ( PARTITION BY isin ORDER BY ts, id ) AS value4,
         LAST_VALUE(value5) IGNORE NULLS OVER ( PARTITION BY isin ORDER BY ts, id ) AS value5,
         LAST_VALUE(value6) IGNORE NULLS OVER ( PARTITION BY isin ORDER BY ts, id ) AS value6,
         ROW_NUMBER() OVER ( PARTITION BY isin ORDER BY ts DESC, id DESC ) AS rn
  FROM   table_name
)
WHERE rn = 1

或者,您可以使用MAX() ... KEEP ( DENSE_RANK ... )

SELECT MAX(ts) AS ts,
       MAX(id) KEEP ( DENSE_RANK LAST ORDER BY ts, id ) AS id,
       isin,
       MAX(value1) KEEP (
         DENSE_RANK FIRST
         ORDER BY
           CASE WHEN value1 IS NOT NULL THEN ts END DESC NULLS LAST,
           id DESC
       ) AS value1,
       MAX(value2) KEEP (
         DENSE_RANK FIRST
         ORDER BY
           CASE WHEN value2 IS NOT NULL THEN ts END DESC NULLS LAST,
           id DESC
       ) AS value2,
       MAX(value3) KEEP (
         DENSE_RANK FIRST
         ORDER BY
           CASE WHEN value3 IS NOT NULL THEN ts END DESC NULLS LAST,
           id DESC
       ) AS value3,
       MAX(value4) KEEP (
         DENSE_RANK FIRST
         ORDER BY
           CASE WHEN value4 IS NOT NULL THEN ts END DESC NULLS LAST,
           id DESC
       ) AS value4,
       MAX(value5) KEEP (
         DENSE_RANK FIRST
         ORDER BY
           CASE WHEN value5 IS NOT NULL THEN ts END DESC NULLS LAST,
           id DESC
       ) AS value5,
       MAX(value6) KEEP (
         DENSE_RANK FIRST
         ORDER BY
           CASE WHEN value6 IS NOT NULL THEN ts END DESC NULLS LAST,
           id DESC
       ) AS value6
FROM   table_name
GROUP BY isin

其中的示例数据:

CREATE TABLE table_name ( ts, id, isin, value1, value2, value3, value4, value5, value6 ) AS
SELECT SYSDATE - 5, 1, 1, 'A',  'B',  'C',  'D',  'E',  'F'  FROM DUAL UNION ALL
SELECT SYSDATE - 4, 2, 1, NULL, NULL, 'G',  NULL, NULL, NULL FROM DUAL UNION ALL
SELECT SYSDATE - 3, 3, 1, NULL, 'H',  NULL, NULL, 'I',  NULL FROM DUAL UNION ALL
SELECT SYSDATE - 2, 4, 1, NULL, NULL, NULL, 'J',  NULL, NULL FROM DUAL UNION ALL
SELECT SYSDATE - 2, 5, 2, 'K',  'L',  'M',  'N',  'O',  'P'  FROM DUAL UNION ALL
SELECT SYSDATE - 1, 6, 2, NULL, 'Q',  NULL, NULL, NULL, NULL FROM DUAL UNION ALL
SELECT SYSDATE - 0, 7, 2, NULL, NULL, NULL, 'R',  NULL, NULL FROM DUAL;

两个输出:

TS        | ID | ISIN | VALUE1 | VALUE2 | VALUE3 | VALUE4 | VALUE5 | VALUE6
:-------- | -: | ---: | :----- | :----- | :----- | :----- | :----- | :-----
09-NOV-20 |  4 |    1 | A      | H      | G      | J      | I      | F     
11-NOV-20 |  7 |    2 | K      | Q      | M      | R      | O      | P     

db <>提琴here

答案 1 :(得分:1)

就这样:

SELECT SUBSTR(LISTAGG("col1" ,', ') WITHIN GROUP (ORDER BY "col1"),-1,1)as value1,
 SUBSTR(LISTAGG("col2" ,', ') WITHIN GROUP (ORDER BY "col2"),-1,1)as value2,
 SUBSTR(LISTAGG("col3" ,', ') WITHIN GROUP (ORDER BY "col3"),-1,1)as value3,
 SUBSTR(LISTAGG("col4" ,', ') WITHIN GROUP (ORDER BY "col4"),-1,1)as value4,
 SUBSTR(LISTAGG("col5" ,', ') WITHIN GROUP (ORDER BY "col5"),-1,1)as value5,
 SUBSTR(LISTAGG("col6" ,', ') WITHIN GROUP (ORDER BY "col6"),-1,1)as value6

FROM Table1
group by "isin";

检查:http://sqlfiddle.com/#!4/f02bd/5

答案 2 :(得分:0)

您可以按以下方式使用KEEP子句:

SELECT ISIN, 
       MAX(VALUE1) KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN VALUE1 IS NULL THEN NULL ELSE "TIMESTAMP" END DESC NULLS LAST) AS VALUE1,
       MAX(VALUE2) KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN VALUE2 IS NULL THEN NULL ELSE "TIMESTAMP" END DESC NULLS LAST) AS VALUE2,
       ...
  FROM YOUR_TABLE
GROUP BY ISIN;