2012-04-20 52 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