Question

Most databases have something like a GREATEST function, which can be useful some times. At least these databases don't have such a function:

  • Derby
  • SQL Server
  • Sybase ASE
  • Sybase SQL Anywhere

For SQL Server and Sybase SQL Anywhere, the function can be simulated using subqueries and UNION ALL, as can be seen in this question here. An example:

-- 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

But this doesn't work in Sybase ASE. Apparently, the subqueries don't have access to the outer query's my_table reference. The error I get is

The column prefix 'my_table' does not match with a table name or alias name used in the query. Either the table is not specified in the FROM clause or it has a correlation name which must be used instead

Note, this problem does not appear with Sybase SQL Anywhere. Any idea what's wrong here and how I could re-write the query?

I'd like to avoid

  • Stored functions, as I may not have the necessary grants to create them
  • Lengthy CASE expressions, as the expression length of the combined permutation of all comparisons needed with nested CASE expressions is at least O(n^2) when n is the number of parameters for GREATEST
Was it helpful?

Solution

As I understand it, the logic (ignoring nulls) is

SELECT CASE 
          WHEN field1 >= field2 
               AND field1 >= field3
             THEN field1
          WHEN field2 >= field3
             THEN field2
          ELSE field3
       END AS greatest
  FROM my_table;

...but should only return null when all values are null.


I think this is more how I'd like to be able do things (although, Sybase ASE does not support common table expressions):

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;

OTHER TIPS

In that case, I'll add one 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

The following SQL clause is even more concise than onedaywhen's answer, although they're semantically equivalent:

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;

This is finally a rare and yet nice use-case for those quantifiers that hardly anyone uses in SQL. See also this question:

Are SQL ANY and SOME keywords synonyms in all SQL dialects?

Unfortunately, this syntax is not supported in all SQL dialects, as the ALL quantifier ususally expects a <table subquery>

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top