Estou no Postgres 13.5.
Os registros sempre têm um number
(tipo: integer
) e, opcionalmente, uma única letter
AZ (tipo: varchar(1)
– não char
por motivos de estrutura).
Os registros geralmente são classificados number ASC, letter ASC NULLS FIRST
. A sequência pode ter lacunas. As letras ausentes são representadas como NULL.
Por exemplo, você pode obter este pedido: 1, 1A, 1B, 2, 10, 10A, 10C
Agora, quero fazer coisas como encontrar os dois registros "à direita" de um determinado registro. Portanto, se o registro fornecido for o número 2, quero encontrar 10 e 10A no exemplo acima.
seria conveniente se eu pudesse consultar uma condição como (pseudo código):number > $given_number OR (number = $given_number AND letter > $given_letter NULLS FIRST)
Isso não funciona como está escrito, é claro. Quais são as maneiras que eu poderia conseguir isso?
Prefiro não mesclar as colunas ou adicionar novas colunas.
Soluções que consigo pensar:
- Selecione uma lista de IDs de registro no SQL, use a lógica do aplicativo fora do banco de dados para localizar IDs dos próximos dois registros e faça uma segunda consulta para localizar apenas aqueles.
- Uma condição mais longa que explica explicitamente NULLs, algo como
WHERE number > $given_number OR (number = $given_number AND (($given_letter IS NULL AND letter IS NOT NULL) OR letter > $given_letter)) ORDER BY number ASC, letter ASC NULLS FIRST LIMIT 2
- Aglutinando NULLs, algo como
WHERE number > $given_number OR (number = $given_number AND letter > COALESCE($given_letter, '')) ORDER BY number ASC, letter ASC NULLS FIRST LIMIT 2
Alguma ideia melhor? Ou alguma opinião sobre estes?
Se você puder converter valores NULL em
letter
strings vazias (''
) , tudo se encaixará. A string vazia é classificada antes de qualquer outro valor na ordem de classificação padrão.Isso supondo que você não tenha strings vazias e valores NULL ( o que seria ainda mais lamentável).
Sua ordem de classificação:
Torna-se apenas:
db<>fique aqui
Observe o uso de comparação de valor de linha . Ver:
Faça backup com um
UNIQUE
Ãndice ou PK em(number, letter)
, e você está de ouro.Se você não puder limpar a definição da tabela, ainda há uma solução alternativa:
Pode até ser suportado com um Ãndice de várias colunas correspondente. Mas, em vez disso, mantenha-o simples e converta seus valores NULL.
A parte :
para cartas de AZ, o tipo
"char"
seria ainda um pouco mais eficiente - decididamente distinto dechar
, o que nunca é útil. (Mas suas "razões de estrutura" provavelmente se opõem a isso.) Veja:A função window
LEAD(column_name,1) OVER (ORDER BY ...)
eLEAD(column_name,2) OVER (ORDER BY ...)
pode fazer o que você deseja, se:A forma da consulta seria