Dans de nombreux langages de programmation, vous pouvez comparer des chaînes en utilisant des opérateurs comme>,> =, <etc ... et le langage basera la comparaison sur la position de la lettre dans l'alphabet.
Par exemple en PHP
if ('a' < 'b') {
echo 'Yes';
} else {
echo 'No';
}
> Yes
Cependant en postgres ou mysql
SELECT
CASE WHEN 'a' < 'b' THEN 'yes' END
FROM table
Output: null
J'ai une table avec des chaînes que je dois comparer les unes aux autres via SQL.
Par exemple: 6,2 (5a) 6,2 (5b) - ce serait supérieur à 6,2 (5a) ou 6,2 (15) - ce serait supérieur à 6,2 (5a)
J'ai pensé attribuer un numéro à une lettre à l'aide d'une expression rationnelle, mais cela casserait les comparaisons lorsqu'il n'y a pas de lettre.
Comment procéderiez-vous uniquement en SQL?
[~ # ~] note [~ # ~]: La réponse originale s'est déclenchée sur un hareng rouge.
Une comparaison simple trie caractère par caractère.
select 'a1' < 'a9'; -- true because 'a' = 'a' and '1' < '9'.
... mais passe rapidement au pot.
select 'a10' < 'a9'; -- also true for the same reason.
Ce que vous voulez est un tri naturel où les parties de chaîne sont comparées en tant que chaînes et les nombres sont comparés en tant que nombres. Faire un tri naturel en SQL n'est pas la chose la plus simple. Vous avez besoin de largeurs de champ fixes pour trier chaque sous-chaîne séparément, ou peut-être quelque chose avec des expressions régulières ...
Heureusement, il y a pg_natural_sort_order , une extension Postgres qui implémente un tri naturel efficace.
Si vous ne pouvez pas installer d'extensions, vous pouvez utiliser une procédure stockée comme btrsort by 2kan.
CREATE FUNCTION btrsort_nextunit(text) RETURNS text AS $$
SELECT
CASE WHEN $1 ~ '^[^0-9]+' THEN
COALESCE( SUBSTR( $1, LENGTH(SUBSTRING($1 FROM '[^0-9]+'))+1 ), '' )
ELSE
COALESCE( SUBSTR( $1, LENGTH(SUBSTRING($1 FROM '[0-9]+'))+1 ), '' )
END
$$ LANGUAGE SQL;
CREATE FUNCTION btrsort(text) RETURNS text AS $$
SELECT
CASE WHEN char_length($1)>0 THEN
CASE WHEN $1 ~ '^[^0-9]+' THEN
RPAD(SUBSTR(COALESCE(SUBSTRING($1 FROM '^[^0-9]+'), ''), 1, 12), 12, ' ') || btrsort(btrsort_nextunit($1))
ELSE
LPAD(SUBSTR(COALESCE(SUBSTRING($1 FROM '^[0-9]+'), ''), 1, 12), 12, ' ') || btrsort(btrsort_nextunit($1))
END
ELSE
$1
END
;
$$ LANGUAGE SQL;
Bien qu'il ne fournisse pas d'opérateur de comparaison et je ne vais pas prétendre le comprendre. Cela vous permet de l'utiliser dans un order by
.
select * from things order by btrsort(whatever);
Pour éviter que vos requêtes triées naturellement ne se transforment en boue sur de grandes tables, vous pouvez créer un index btree sur le résultat de cette fonction .
create index things_whatever_btrsort_idx ON things( btrsort(whatever) );
SELECT CASE WHEN 'a' < 'b' THEN 'yes' END FROM table Output: null
Cela ne produira rien si la table est vide. Vous n'avez pas besoin d'un tableau pour tester les instructions select.
SELECT
CASE WHEN 'a' < 'b' THEN 'yes' END -- yes