Comment simuler GREATEST () dans Sybase ASE?
-
27-10-2019 - |
Question
La plupart des bases de données ont quelque chose comme un GREATEST
fonction, qui peut être utile de temps certains. Au moins ces bases de données ne sont pas une telle fonction:
- Derby
- SQL Server
- Sybase ASE
- Sybase SQL Anywhere
Pour SQL Server et Sybase SQL Anywhere, la fonction peut être simulée à l'aide et les sous-requêtes UNION ALL
, comme on peut le voir dans cette question ici . Un exemple:
-- SELECT GREATEST(field1, field2, field3) FROM my_table
SELECT (SELECT MAX(c) FROM
(SELECT my_table.field1 AS c UNION ALL
SELECT my_table.field2 UNION ALL
SELECT my_table.field3) T) AS greatest
FROM my_table
Mais cela ne fonctionne pas dans Sybase ASE. Apparemment, les sous-requêtes n'ont pas accès à la référence my_table
de la requête externe. L'erreur que je reçois est
Le préfixe de colonne « my_table » ne correspond pas à un nom de nom de table ou alias utilisé dans la requête. Soit la table ne soit pas prévue dans la clause FROM ou il a un nom de corrélation qui doit être utilisé à la place
Remarque, ce problème ne semble pas avec Sybase SQL Anywhere. Toute idée de ce qui ne va pas ici et comment je pourrais réécrire la requête?
Je voudrais éviter
- Fonctions stockées, comme je ne peux pas avoir les subventions nécessaires pour les créer
- expressions
CASE
longues, comme la longueur d'expression de la permutation combinée de toutes les comparaisons nécessaires avec les expressions deCASE
imbriquées est au moinsO(n^2)
lorsquen
est le nombre de paramètres pourGREATEST
La solution
Si je comprends bien, la logique (sans tenir compte des valeurs nulles) est
SELECT CASE
WHEN field1 >= field2
AND field1 >= field3
THEN field1
WHEN field2 >= field3
THEN field2
ELSE field3
END AS greatest
FROM my_table;
... mais ne devrait revenir nulle lorsque toutes les valeurs sont nulles.
Je pense que cela est plus que je voudrais être en mesure des choses faire (bien que, Sybase ASE ne supporte pas les expressions de table communes):
WITH my_table
AS
(
SELECT *
FROM (
VALUES ('A', 1, 2, 3),
('B', 2, 3, 1),
('C', 3, 1, 2),
('D', NULL, 2, 3),
('E', NULL, NULL, 3),
('F', NULL, 3, NULL),
('G', 1, NULL, 3),
('H', 1, 3, NULL),
('X', NULL, NULL, NULL)
) AS T (ID, field1, field2, field3)
),
T1
AS
(
SELECT ID, field1 AS field_n
FROM my_table
UNION
SELECT ID, field2 AS field_n
FROM my_table
UNION
SELECT ID, field3 AS field_n
FROM my_table
)
SELECT ID, MAX(field_n) AS greatest
FROM T1
GROUP
BY ID;
Autres conseils
Dans ce cas, je vais ajouter un CASE
supplémentaire.
SELECT
CASE WHEN field1 IS NOT NULL
AND field2 IS NOT NULL
AND field3 IS NOT NULL THEN
CASE WHEN field1 >= field2
AND field1 >= field3
THEN field1
WHEN field2 >= field3
THEN field2
ELSE field3
END
ELSE
NULL
END AS greatest
FROM my_table
La clause SQL suivante est encore plus concise que la réponse onedaywhen , bien qu'ils soient sémantiquement équivalentes:
SELECT CASE WHEN field1 >= ALL(field2, field3, field4) THEN field1
WHEN field2 >= ALL( field3, field4) THEN field2
WHEN field3 >= ALL( field4) THEN field3
ELSE field4
END AS greatest
FROM my_table;
Ceci est enfin un cas d'utilisation rare et pourtant agréable pour les quantificateurs que presque personne utilise dans SQL. Voir aussi cette question:
sont des mots clés SQL ANY et certains synonymes dans tous les dialectes SQL?
Malheureusement, cette syntaxe est pas prise en charge dans tous les dialectes SQL, comme le quantificateur ALL
attend ususally un <table subquery>