仅选择“最完整”记录

时间:2018-11-26 16:10:00

标签: sql postgresql

我需要解决以下问题。

假设我有一个包含4个字段的表,分别称为a,b,c,d。

我有以下记录:

-------------------------------------
   a   |    b    |    c    |    d  
-------------------------------------
   1   |    2    |         |             row 1 
   1   |    2    |    3    |    4        row 2 
   1   |    2    |         |    4        row 3
   1   |    2    |    3    |             row 4  

可以观察到,第1、3、4行是第2行的“子记录”。

我想做的是仅提取第二行。

能帮我吗?

提前感谢您的回答

编辑:我需要更具体些。

我也可能遇到以下情况:

-------------------------------------
   a   |    b    |    c    |    d  
-------------------------------------
   1   |    2    |         |             row 1 
   1   |    2    |         |    4        row 2 
   1   |         |         |    4        row 3

我需要提取第二行的地方,

-------------------------------------
   a   |    b    |    c    |    d  
-------------------------------------
   1   |    2    |         |             row 1 
   1   |    2    |    3    |             row 2 
   1   |         |    3    |             row 3

再次,我需要提取第二行。

对夫妻一样


   a   |    b    |    c    |    d  
-------------------------------------
   1   |         |         |             row 1 
   1   |         |    3    |             row 2 
       |         |    3    |             row 3

,以此类推。

(当然,现在总是第二行)

5 个答案:

答案 0 :(得分:1)

使用不存在,可以过滤出重复性更好的记录。

let neededHeight = width / ratio // This is a CGFloat like 133.2353
constraintPictureHeight.constant = neededHeight // Causes constraint error
constraintPictureHeight.constant = ceil(neededHeight) // All good!
create table abcd (
 a int,
 b int,
 c int,
 d int
);
insert into abcd (a, b, c, d) values
 (1, 2, null, null)
,(1, 2, 3, 4)
,(1, 2, null, 4)
,(1, 2, 3, null)

,(2, 3, null,null)
,(2, 3, null, 5)
,(2, null, null, 5) 

,(3, null, null, null)
,(3, null, 5, null)
,(null, null, 5, null)
 a |    b |    c |    d
-: | ---: | ---: | ---:
 1 |    2 |    3 |    4
 2 |    3 | null |    5
 3 | null |    5 | null

db <>提琴here

答案 1 :(得分:0)

根据您的定义,大多数完整的行是具有最少空列的行:

SELECT * FROM tablename
WHERE (
    (CASE WHEN a IS NULL THEN 0 ELSE 1 END) + 
    (CASE WHEN b IS NULL THEN 0 ELSE 1 END) + 
    (CASE WHEN c IS NULL THEN 0 ELSE 1 END) + 
    (CASE WHEN d IS NULL THEN 0 ELSE 1 END)
) =
(SELECT MAX(
    (CASE WHEN a IS NULL THEN 0 ELSE 1 END) + 
    (CASE WHEN b IS NULL THEN 0 ELSE 1 END) + 
    (CASE WHEN c IS NULL THEN 0 ELSE 1 END) + 
    (CASE WHEN d IS NULL THEN 0 ELSE 1 END)) 
FROM tablename)

答案 2 :(得分:0)

嗯。 。 。我认为您可以使用not exists

with t as (
      select t.*, row_number() over (order by a) as id
      from t
     )
select t.*
from t
where not exists (select 1
                  from t t2
                  where ((t2.a is not distinct from t.a or t2.a is not null and t.a is null) and
                         (t2.b is not distinct from  t.b or t2.b is not null and t.b is null) and
                         (t2.c is not distinct from  t.c or t2.c is not null and t.c is null) and
                         (t2.d is not distinct from  t.d or t2.d is not null and t.d is null)
                        ) and
                        t2.id <> t.id
                 );

逻辑是不存在与值匹配的特定行

Here是db <>小提琴。

答案 3 :(得分:0)

您将需要为每一行计算一个“完成索引”。在您提供的示例中,您可能会使用以下内容:

   (CASE WHEN a IS NULL THEN 0 ELSE 1) +
   (CASE WHEN b IS NULL THEN 0 ELSE 1) +
   (CASE WHEN c IS NULL THEN 0 ELSE 1) +
   (CASE WHEN d IS NULL THEN 0 ELSE 1) AS CompletionIndex

然后选择由CompletionIndex降序排列的前1个。

显然,这在很多列上都不太可扩展。但是,如果您有大量的稀疏填充列,则可以考虑为数据使用基于行而不是基于列的结构。这种设计将使计算每个实体的非NULL值的数量变得更加容易。

答案 4 :(得分:0)

正如戈登·利诺夫(Gordon Linoff)所说,我们确实必须使用一些不存在的东西,

编辑使用EXCEPT帮助

这可能有效...

SELECT * from table1 
EXCEPT
(
SELECT t1.*
FROM table1 t1
JOIN table1 t2
ON  COALESCE(t1.a, t2.a, -1) = COALESCE(t2.a, -1)
AND COALESCE(t1.b, t2.b, -1) = COALESCE(t2.b, -1)
AND COALESCE(t1.c, t2.c, -1) = COALESCE(t2.c, -1)
AND COALESCE(t1.d, t2.d, -1) = COALESCE(t2.d, -1)
)

在这里,t1是每个子集行。

注意:我们假设值-1为前哨值,并且在任何列中都不会出现。