使用最少数量的null选择distinct的最简单方法

时间:2018-01-22 20:01:43

标签: sql

我想在一个包含500k行和10列的表上创建一个视图。在该表中,存在重复的id但具有不同的信息量,因为一些列是NULL。我的目标是在重复的情况下保留一列,但希望保留一个具有较少NULL值的列。

让我用一个简单的例子解释一下。我正在处理类似的查询。

CREATE TABLE test (ID INT, b char(1), c char (1), d char(1))

INSERT INTO test(ID,b,c,d) VALUES 
(1,NULL,NULL,NULL),
(1,'B', NULL,NULL),
(1,'B','C',NULL),
(1,'B','C','D'),
(2,'E','F',NULL),
(2,'E',NULL,NULL),
(3,NULL,NULL,NULL),
(3,'G',NULL,NULL)

SELECT DISTINCT ID,b,c,d FROM test

DROP TABLE test

结果是

ID  b     c     d
--------------------
1   NULL  NULL  NULL
1   B     NULL  NULL
1   B     C     NULL
1   B     C     D
2   E     F     NULL
2   E     NULL  NULL
3   NULL  NULL  NULL
3   G     NULL  NULL

但是,我想看到的输出是

ID  b     c     d
--------------------
1   B     C     D
2   E     F     NULL
3   G     NULL  NULL

因此,基于id并且如果有重复项,我希望拥有空值最少的行。怎么可能?

非常感谢

2 个答案:

答案 0 :(得分:1)

如果你想要NULL s的行数最少的那一行,你基本上可以算一下:

select t.*
from test t
order by ( (case when b is null then 1 else 0 end) +
           (case when c is null then 1 else 0 end) +
           (case when d is null then 1 else 0 end)
         ) desc
fetch first 1 row only;

但是,如果你想要每个id一行,每列中有一个非NULL值(如果可用),那么@ maSTAShuFu的答案是合适的。

编辑:

如果您希望每个客户一行,则只需使用row_number()

select t.*
from (select t.*,
             row_number() over (partition by client_id
                                order by ( (case when b is null then 1 else 0 end) +
                                           (case when c is null then 1 else 0 end) +
                                           (case when d is null then 1 else 0 end)
                                         ) desc
                                ) as seqnum
      from t
     ) t
where seqnum = 1;

答案 1 :(得分:0)

使用MAX。

SELECT
  MAX(ID) ID,
  MAX(B) B,
  MAX(C) C,
  MAX(D) D
FROM test