Eu tenho uma consulta SQL simples no PostgreSQL 8.3 que pega um monte de comentários. Eu forneço uma lista classificada de valores para a IN
construção na WHERE
cláusula:
SELECT * FROM comments WHERE (comments.id IN (1,3,2,4));
Isso retorna comentários em uma ordem arbitrária que, no meu caso, é como ids 1,2,3,4
.
Quero que as linhas resultantes classificadas como na lista da IN
construção: (1,3,2,4)
.
Como conseguir isso?
sql
postgresql
sql-order-by
sql-in
quebra-nozes
fonte
fonte
Respostas:
Você pode fazer isso facilmente com (introduzido no PostgreSQL 8.2) VALUES (), ().
A sintaxe será assim:
fonte
with ordered_products as (select row_number() OVER (ORDER BY whatever) as reportingorder, id from comments) ... ORDER BY reportingorder
.Só porque é tão difícil de encontrar e precisa ser espalhado: no mySQL isso pode ser feito de maneira muito mais simples , mas não sei se funciona em outro SQL.
fonte
ERROR: cannot pass more than 100 arguments to a function
No Postgres 9.4 ou posterior, isso é provavelmente mais simples e rápido :
Usando o novo
WITH ORDINALITY
, que @a_horse já mencionou .Não precisamos de uma subconsulta, podemos usar a função de retorno de conjunto como uma tabela.
Uma string literal para entregar na matriz em vez de um construtor ARRAY pode ser mais fácil de implementar com alguns clientes.
Explicação detalhada:
fonte
Eu acho que assim é melhor:
fonte
... order by id=? desc, id=? desc, id=? desc
e parece funcionar bem :-)Com o Postgres 9.4, isso pode ser feito um pouco mais curto:
Ou um pouco mais compacto sem uma tabela derivada:
Removendo a necessidade de atribuir / manter manualmente uma posição para cada valor.
Com o Postgres 9.6, isso pode ser feito usando
array_position()
:O CTE é usado para que a lista de valores precise ser especificada apenas uma vez. Se isso não for importante, também pode ser escrito como:
fonte
IN
lista daWHERE
cláusula novamente naORDER BY
cláusula, o que torna esta a melhor resposta imho ... Agora só para encontrar algo semelhante para MySQL ...order by array_position(array[42,48,43], c.id::int);
que pode levar a erros em alguns casos.array_position(array[42, 48, 43]::bigint[], c.id::bigint)
, então não há necessidade de truncarbigint
aint
.Outra maneira de fazer isso no Postgres seria usar a
idx
funçãoNão se esqueça de criar a
idx
função primeiro, conforme descrito aqui: http://wiki.postgresql.org/wiki/Array_Indexfonte
CREATE EXTENSION intarray;
.enable_extension
permitirá que você ative isso desde que o usuário do aplicativo seja um membro dords_superuser
grupo.No Postgresql:
fonte
position(id::text in '123,345,3,678')
. O ID3
corresponderá antes do ID345
, não é?Ao pesquisar isso um pouco mais, encontrei esta solução:
No entanto, isso parece bastante detalhado e pode ter problemas de desempenho com grandes conjuntos de dados. Alguém pode comentar sobre essas questões?
fonte
IN
cláusula? porque eu tenho que fazer isso por milhares de registros.Para fazer isso, acho que você provavelmente deveria ter uma tabela "ORDER" adicional que define o mapeamento dos IDs por ordem (efetivamente fazendo o que sua resposta à sua própria pergunta dizia), que você pode usar como uma coluna adicional no seu você pode então escolher.
Dessa forma, você descreve explicitamente a ordem que deseja no banco de dados, onde deveria estar.
fonte
sans SEQUENCE, funciona apenas no 8.4:
fonte
ou se você prefere o mal ao bem:
fonte
E aqui está outra solução que funciona e usa uma tabela constante ( http://www.postgresql.org/docs/8.3/interactive/sql-values.html ):
Mas, novamente, não tenho certeza de que isso tenha desempenho.
Eu tenho um monte de respostas agora. Posso obter algumas votações e comentários para saber qual é o vencedor!
Obrigado a todos :-)
fonte
[EDITAR]
O unnest ainda não está embutido no 8.3, mas você pode criar um você mesmo (a beleza de qualquer *):
essa função pode funcionar em qualquer tipo:
fonte
Leve melhoria em relação à versão que usa uma sequência, eu acho:
fonte
aqui, [bbs] é a tabela principal que possui um campo chamado ids e ids é a matriz que armazena o comments.id.
passado no postgresql 9.6
fonte
Vamos ter uma impressão visual sobre o que já foi dito. Por exemplo, você tem uma tabela com algumas tarefas:
E você deseja ordenar a lista de tarefas por seu status. O status é uma lista de valores de sequência:
O truque é atribuir um valor a cada valor de status e ordenar a lista numérica:
O que leva a:
Crédito @ user80168
fonte
Concordo com todos os outros pôsteres que dizem "não faça isso" ou "SQL não é bom nisso". Se você deseja classificar por algum aspecto dos comentários, adicione outra coluna inteira a uma de suas tabelas para manter seus critérios de classificação e classificar por esse valor. por exemplo, "ORDER BY comments.sort DESC" Se você quiser classificá-las em uma ordem diferente todas as vezes, então ... SQL não será para você neste caso.
fonte