Pergunta

Eu tenho um banco de dados postgres com uma tabela de usuário (userid, nome, sobrenome) e uma tabela de metadados de usuário (userid, código, conteúdo, data e hora de criação).Eu armazeno diversas informações sobre cada usuário na tabela usermetadata por código e mantenho um histórico completo.então, por exemplo, um usuário (userid 15) possui os seguintes metadados:

15, 'QHS', '20', '2008-08-24 13:36:33.465567-04'  
15, 'QHE', '8', '2008-08-24 12:07:08.660519-04'  
15, 'QHS', '21', '2008-08-24 09:44:44.39354-04'  
15, 'QHE', '10', '2008-08-24 08:47:57.672058-04'  

Preciso buscar uma lista de todos os meus usuários e o valor mais recente de cada um dos vários códigos de metadados do usuário.Eu fiz isso programaticamente e foi, claro, terrivelmente lento.O melhor que consegui fazer em SQL foi juntar sub-seleções, que também eram lentas e tive que fazer uma para cada código.

Foi útil?

Solução

Suponho que você não esteja disposto a modificar seu esquema, então receio que minha resposta não seja de muita ajuda, mas aqui vai...

Uma solução possível seria deixar o campo de hora vazio até que fosse substituído por um valor mais recente, quando você inserisse a 'data de descontinuação'.Outra forma é expandir a tabela com uma coluna 'ativa', mas isso introduziria alguma redundância.

A solução clássica seria ter os campos 'Valid-From' e 'Valid-To', onde os campos 'Valid-To' ficam em branco até que alguma outra entrada se torne válida.Isso pode ser resolvido facilmente usando gatilhos ou similares.Usar restrições para garantir que haja apenas um item de cada tipo válido garantirá a integridade dos dados.

Comum a estes é que existe uma única maneira de determinar o conjunto de campos atuais.Você simplesmente selecionaria todas as entradas com o usuário ativo e um NULL 'Valid-To' ou 'data de descontinuação' ou um verdadeiro 'ativo'.

Você pode estar interessado em dar uma olhada na entrada da Wikipedia em bancos de dados temporais e o artigo Um glossário de consenso de conceitos de banco de dados temporal.

Outras dicas

Na verdade, isso não é tão difícil de fazer no PostgreSQL porque ele tem o "DISTINTO EM" cláusula em sua sintaxe SELECT (DISTINCT ON não é SQL padrão).

SELECT DISTINCT ON (code) code, content, createtime
FROM metatable
WHERE userid = 15
ORDER BY code, createtime DESC;

Isso limitará os resultados retornados ao primeiro resultado por código exclusivo e, se você classificar os resultados pelo tempo de criação decrescente, obterá o mais recente de cada um.

Uma subseleção é a maneira padrão de fazer esse tipo de coisa.Você só precisa de uma restrição exclusiva em UserId, código e data - e então você pode executar o seguinte:

SELECT * 
FROM Table
JOIN (
   SELECT UserId, Code, MAX(Date) as LastDate
   FROM Table
   GROUP BY UserId, Code
) as Latest ON
   Table.UserId = Latest.UserId
   AND Table.Code = Latest.Code
   AND Table.Date = Latest.Date
WHERE
   UserId = @userId
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top