【问题标题】:SQL - Select non-null value based on the most recent dateSQL - 根据最近的日期选择非空值
【发布时间】:2019-03-29 06:23:41
【问题描述】:

我正在使用 SQL 查询来获取最新的非空值,除非全部为空 这基于“id”列。

考虑这张表:

create table calc
(
     id int, 
     tms date,
     col1 int, 
     col2 int, 
     col3 int
);

insert into calc 
values (1, '1/1/2000', 100, 333, null),
       (1, '3/3/2000', null, 222, null),
       (1, '2/2/2000', 300, 111, null);

预期输出:

1,'3/3/2000',300,222,null

下面是我运行的查询,但它只返回最大日期的行

select 
    c.id, max_dt, col1, col2, col3
from 
    calc c
inner join 
    (select id, max(tms) as max_Dt
     from calc
     group by id) a on a.id = c.id and a.max_dt = tms;

实际输出:

1,'3/3/2000',null,222,null

关于如何获得所需解决方案的任何想法?

【问题讨论】:

  • 请正确标记。哪个 DBMS Oracle 或 SQL-Server ..?
  • 看起来适合 APPLY 的工作。

标签: sql oracle


【解决方案1】:

这是一种通用的 SQL 方法(“困难方法”)。如果您提供您正在使用的 DBMS,这可能会得到改善。

select id,
    max(tms) as max_dt,
    (select col1 
        from calc c1 
        where c1.id = c.id and c1.tms = 
        (select max(tms) from calc where id = c1.id and col1 is not null) ) max_col1,
    (select col2 
        from calc c2 
        where c2.id = c.id and c2.tms = 
        (select max(tms) from calc where id = c2.id and col2 is not null) ) max_col2,
    (select col3 
        from calc c3 
        where c3.id = c.id and c3.tms = 
        (select max(tms) from calc where id = c3.id and col3 is not null) ) max_col3
from calc c
group by id;

【讨论】:

    【解决方案2】:
      SELECT t11.id,
               t14.tms,
               t11.col1,
               t12.col2,
               t13.col3
        FROM
          (SELECT calc.id,
                  col1
           FROM calc
           INNER JOIN
             (SELECT id,
                     max(tms) tms
              FROM calc
              WHERE col1 IS NOT NULL
              GROUP BY id)AS t1 ON t1.id = calc.id
           AND t1.tms = calc.tms) AS t11
        LEFT JOIN
          (SELECT calc.id,
                  col2
           FROM calc
           INNER JOIN
             (SELECT id,
                     max(tms) tms
              FROM calc
              WHERE col2 IS NOT NULL
              GROUP BY id)AS t2 ON t2.id = calc.id
           AND t2.tms = calc.tms) AS t12 ON t11.id = t12.id
        LEFT JOIN
          (SELECT calc.id,
                  col3
           FROM calc
           INNER JOIN
             (SELECT id,
                     max(tms) tms
              FROM calc
              WHERE col3 IS NOT NULL
              GROUP BY id)AS t3 ON t3.id = calc.id
           AND t3.tms = calc.tms) AS t13 ON t11.id = t13.id
        INNER JOIN
          (SELECT id,
                  max(tms) tms
           FROM calc
           GROUP BY id)AS t14 ON t11.id = t14.id
    

    【讨论】:

      【解决方案3】:

      我对您的原始查询进行了一些修改。正如您所写,在上面显示的输出中的第三个位置有 null 是正常的,它看起来像:

      select * from calc where id =1 and tms = '3/3/2000');
      

      你可以试试这个:

      select c.id, nvl(tms,max_dt) tms, nvl(col1,mcol1) col1, nvl(col2,mcol2) col2, 
      nvl(col3,mcol3) col3
      from 
      calc c
      inner join 
      (select id, max(tms) max_Dt, max(col1) mcol1, max(col2) mcol2, max(col3) mcol3 
       from calc
       group by id) a on a.id = c.id and a.max_dt = tms;
      

      希望对你有帮助。

      【讨论】:

      • 不客气 ;) 很高兴您解决了问题。
      • 如果您要对 40,000 行上的 10 列执行操作,此解决方案会非常缓慢..
      【解决方案4】:

      您完全可以在没有子查询的情况下执行此操作,使用 keep 关键字:

      select id, max(tms),
             max(col1) keep (dense_rank first order by (case when col1 is not null then 1 else 2 end), tms desc) as col1,
             max(col2) keep (dense_rank first order by (case when col2 is not null then 1 else 2 end), tms desc) as col2,
             max(col3) keep (dense_rank first order by (case when col3 is not null then 1 else 2 end), tms desc) as col3
      from calc
      group by id;
      

      Here 是一个 dbfiddle。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-02
        • 1970-01-01
        • 1970-01-01
        • 2021-09-11
        • 2015-06-21
        • 2011-05-04
        相关资源
        最近更新 更多