PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

SQL:como selecionar a linha com valores mais conhecidos?


Vai ser doloroso; muito doloroso.

Sua pergunta não é clara sobre esse problema, mas estou assumindo que o 'id de usuário' ao qual você está se referindo é o nome de usuário. Há modificações consequentes a serem feitas se isso estiver errado.

Como em qualquer consulta complexa, construa-a em etapas.

Estágio 1:Quantos campos não nulos existem por registro?
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

Etapa 2:Qual é o número máximo de campos para um determinado nome de usuário?
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

Etapa 3:selecione (todas) as linhas de um determinado usuário com esse número máximo de campos não nulos:
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;

Agora, se alguém tiver várias linhas com (digamos) todos os três campos preenchidos, todas essas linhas serão retornadas. No entanto, você não especificou nenhum critério para escolher entre essas linhas.

As técnicas básicas aqui podem ser adaptadas a quaisquer requisitos alterados. A chave é construir e testar as subconsultas à medida que avança.

Nenhum desses SQL chegou perto de um DBMS; pode haver bugs nele.

Você não especificou qual DBMS está usando. No entanto, parece que o Oracle não gostará da notação AS usada para aliases de tabela, embora não tenha problemas com AS em aliases de coluna. Se você estiver usando qualquer outro DBMS, não precisa se preocupar com essa pequena excentricidade.