2012-04-20 95 views
1

我有用户的用户名(用户名,性别,date_of_birth,zip),其中用户的ID是永久性的,但用户可以在过去多次注册,有时他会填写所有数据,有时候不会。除此之外,他可以改变居住地(在这种情况下,zip可以改变)。SQL:如何选择具有最知名值的行?

所以查询

SELECT username, sex, date_birth, zip FROM users_log WHERE username IN('user1', 'user2', 'user3') 

返回以下结果:

"user1";"M";"1982-10-04 00:00:00";"6320" 
"user2";"";"";"1537" 
"user3";"";"";"1537" 
"user3";"";"";"1000" 
"user3";"";"";"1000" 
"user3";"";"1979-05-29 00:00:00";"1000" 
"user3";"";"";"1537" 
"user3";"";"1979-05-29 00:00:00";"1000" 
"user1";"";"";"1000" 
"user3";"";"";"1537" 

在这种情况下,用户1,改变了住所;邮政编码改变了;而“属于”他的第二行不包含人口统计数据。用户3也有多个记录,只有两个记录包含人口统计数据。

我想要做的是将用户绑定到包含关于他的最多数据的行,并考虑包含在具有最知名值的行中的zip。有谁知道如何编写适当的查询?

谢谢!

+0

你能向我们提供您的除外什么确切的数据? – Arion 2012-04-20 08:53:46

回答

6

这将是痛苦的;很痛苦。

你的问题不清楚这个问题,但我假设你所指的'用户ID'是用户名。如果这是错误的,则会做出相应的修改。

与任何复杂查询一样,分阶段构建它。

阶段1:每个记录有多少个非空字段?

SELECT username, sex, date_of_birth, zip, 
     CASE WHEN sex   IS NULL THEN 0 ELSE 1 END + 
     CASE WHEN date_of_birth IS NULL THEN 0 ELSE 1 END + 
     CASE WHEN zip   IS NULL THEN 0 ELSE 1 END AS num_non_null_fields 
    FROM users_log 

阶段2:哪一个给定用户名的字段数最多?

SELECT username, MAX(num_non_null_fields) AS num_non_null_fields 
    FROM (SELECT username, sex, date_of_birth, zip, 
       CASE WHEN sex   IS NULL THEN 0 ELSE 1 END + 
       CASE WHEN date_of_birth IS NULL THEN 0 ELSE 1 END + 
       CASE WHEN zip   IS NULL THEN 0 ELSE 1 END AS num_non_null_fields 
      FROM users_log 
     ) AS u 
GROUP BY username 

第3阶段:选择(全部)为与最大数量的非空字段的给定用户行:现在

SELECT u.username, u.sex, u.date_of_birth, u.zip 
    FROM (SELECT username, MAX(num_non_null_fields) AS num_non_null_fields 
      FROM (SELECT username, sex, date_of_birth, zip, 
         CASE WHEN sex   IS NULL THEN 0 ELSE 1 END + 
         CASE WHEN date_of_birth IS NULL THEN 0 ELSE 1 END + 
         CASE WHEN zip   IS NULL THEN 0 ELSE 1 END AS num_non_null_fields 
        FROM users_log 
       ) AS u 
     GROUP BY username 
     ) AS v 
    JOIN (SELECT username, sex, date_of_birth, zip, 
       CASE WHEN sex   IS NULL THEN 0 ELSE 1 END + 
       CASE WHEN date_of_birth IS NULL THEN 0 ELSE 1 END + 
       CASE WHEN zip   IS NULL THEN 0 ELSE 1 END AS num_non_null_fields 
      FROM users_log 
     ) AS u 
    ON u.username = v.username AND u.num_non_null_fields = v.num_non_null_fields; 

,如果有人有(比如说)三个多行填入字段,那么所有这些行将被返回。但是,您尚未指定在这些行之间进行选择的任何标准。

这里的基本技术可以适应任何变化的要求。关键是随时建立和测试子查询。

这个SQL没有一个已经靠近DBMS;它可能会有错误。

您尚未指定您正在使用的DBMS。但是,似乎Oracle不会喜欢用于表别名的AS表示法,尽管它在列别名上对AS没有问题。如果您使用任何其他DBMS,则不必担心这种小偏心。

+0

哇,真是太棒了。 +1 :) – 2012-04-20 09:12:49

5

幸运的是,您正在使用PostgreSQL。它更容易计算由铸造布尔整数填充字段:

SELECT username, 
    ( 
     (sex is not null)::int 
    + (date_birth_birth is not null)::int 
    + (zip is not null)::int 
    )/3.0 as percent_complete 
FROM users_log 

你的代码的目标有这个问题相似:
Postgresql: Calculate rank by number of true OR clauses

相关问题