1

ユーザーのIDが永続的なユーザーのテーブル(username、gender、date_of_birth、zip)がありますが、ユーザーは過去に何度も登録される可能性があり、すべてのデータを入力する場合としない場合があります。それに加えて、彼は居住地を変更することができました (この場合、zip が変更される可能性があります)。

したがって、クエリ

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"

この場合、user1 は住居を変更しました。郵便番号が変更されました。彼に「属する」2 番目の行には、人口統計データが含まれていません。User3 にも複数のレコードがあり、2 つのレコードだけに人口統計データが含まれています。

私がやりたいことは、ユーザーに関するデータを最も多く含む行にユーザーをバインドし、最も既知の値を持つ行に含まれる zip を検討することです。適切なクエリの書き方を知っている人はいますか?

ありがとう!

4

2 に答える 2

6

痛いでしょう。非常に痛いです。

この問題に関するあなたの質問は明確ではありませんが、あなたが参照している「ユーザー ID」はユーザー名であると想定しています。それが間違っている場合は、必然的な修正が必要です。

複雑なクエリと同様に、段階的に構築します。

ステージ 1: レコードごとに null 以外のフィールドがいくつあるか?

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: 最大数の非 null フィールドを持つ特定のユーザーの行を (すべて) 選択します。

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;

ここで、(たとえば) 3 つのフィールドすべてが入力された複数の行がある場合、それらすべての行が返されます。ただし、これらの行から選択する基準を指定していません。

ここでの基本的なテクニックは、変更された要件に適応させることができます。重要なのは、サブクエリを作成してテストすることです。

この SQL はいずれも DBMS に近いものではありません。バグが含まれている可能性があります。

使用している DBMS を指定していません。ただし、オラクルはテーブルの別名に使用される AS 表記を好まないようですが、列の別名の AS には問題はありません。他の DBMS を使用している場合は、そのようなちょっとした偏心について心配する必要はありません。

于 2012-04-20T09:05:50.500 に答える
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: 真の OR 句の数でランクを計算する

于 2012-04-20T09:11:33.850 に答える