¿Cómo simular Greatest () en Sybase ASE?
-
27-10-2019 - |
Pregunta
La mayoría de las bases de datos tienen algo como un GREATEST
función, que puede ser útil en algunas veces. Al menos estas bases de datos no tienen tal función:
- derby
- servidor SQL
- Sybase ase
- Sybase SQL en cualquier lugar
Para SQL Server y Sybase SQL en cualquier lugar, la función se puede simular utilizando subconsules y UNION ALL
, como se puede ver en esta pregunta aquí. Un ejemplo:
-- 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
Pero esto no funciona en Sybase ASE. Aparentemente, las subconsules no tienen acceso a la consulta externa my_table
referencia. El error que recibo es
El prefijo de columna 'my_table' no coincide con un nombre de tabla o nombre de alias utilizado en la consulta. O la tabla no se especifica en la cláusula FROM o tiene un nombre de correlación que debe usarse en su lugar
Tenga en cuenta que este problema no aparece con Sybase SQL en ningún lado. ¿Alguna idea de qué está mal aquí y cómo podría reescribir la consulta?
Me gustaría evitar
- Funciones almacenadas, ya que es posible que no tenga las subvenciones necesarias para crearlas
- Largo
CASE
expresiones, como la longitud de expresión de la permutación combinada de todas las comparaciones necesarias con anidadasCASE
Las expresiones son al menosO(n^2)
cuandon
es el número de parámetros paraGREATEST
Solución
Según tengo entendido, la lógica (ignorando nulos) es
SELECT CASE
WHEN field1 >= field2
AND field1 >= field3
THEN field1
WHEN field2 >= field3
THEN field2
ELSE field3
END AS greatest
FROM my_table;
... pero solo debe devolver nulo cuando todos los valores sean nulos.
Creo que así es más como me gustaría poder hacer las cosas (aunque, Sybase ASE no admite expresiones de tabla comunes):
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;
Otros consejos
En ese caso, agregaré un extra CASE
.
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 siguiente cláusula SQL es aún más concisa que la respuesta de onedaywhen, aunque son semánticamente equivalentes:
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;
Este es finalmente un caso de uso raro y agradable para aquellos cuantificadores que casi nadie usa en SQL. Ver también esta pregunta:
¿SQL son todos y algunos sinónimos de palabras clave en todos los dialectos SQL?
Desafortunadamente, esta sintaxis no es compatible con todos los dialectos SQL, como el ALL
cuantificador de manera usual espera un <table subquery>