Arbitrary sorting in SQL

Sometimes you need to sort in a different manner than SQL's ORDER BY command. Fortunately, there's a hack to do this.

SQL allows for boolean (true/false) values to be interpreted as integers (whole numbers). According to SQL92, the value of "false" is 0 and the value of "true" is 1. In your SELECT statement, you can create a calculated field whose value is the result of a true/false comparison against the other fields, massaged to your liking with additional artithmetic.

Unfortunately, you cannot normally ORDER BY a calculated field because you can't ORDER BY an alias. This generally makes ordering by a calculated field impossible unless you can ORDER BY the exact calculation, but there's a hack around that too!

You can order by a field's alias in a UNION query. To change your normal query into a UNION query, you will have to split it into two queries. The easiest way is to have one SELECT for a known minimum or maximum value of the field being compared (or just SELECT where 1 = 0), and let the other SELECT choose everything else.

Example:

SELECT foo,
 (foo = 1) AS bar
FROM my_table
WHERE (foo = 1)
UNION ALL
SELECT foo, (
 (foo = 2) * 4 +
 (foo = 3) * 2 +
 (foo = 4) * 3
) AS bar
FROM my_table
WHERE (foo <> 1)
ORDER BY bar;

Alternate example

SELECT foo, 0 AS bar
FROM my_table
WHERE (0 = 1)
UNION ALL
SELECT foo, (
 (foo = 1) * 1 +
 (foo = 2) * 4 +
 (foo = 3) * 2 +
 (foo = 4) * 3
) AS bar
FROM my_table
ORDER BY bar;

This example would sort the field "foo" in the order 1,3,4,2 (or reverse that in MSAccess). You can add any number of such sorted fields as you need them.

Exceptions:


Optimizing SQL Queries

SQL queries which include a subquery in the WHERE clause are terribly inefficient. The entire subquery is re-run for each record in the table, leading to O(n^2) inefficiency.

Pseudocode:
for each record {
    re-run entire subquery
}

You can speed up these types of queries by moving the subquery into the SELECT or FROM clause.

 -- Before:
SELECT foo FROM my_table AS A
WHERE (SELECT COUNT(foo) FROM my_table AS B WHERE A.foo = B.foo) = 1;

-- After:
SELECT A.foo
FROM my_table AS A,
(SELECT foo, COUNT(foo) as amt FROM my_table GROUP BY foo) as B
WHERE A.foo = B.foo
and B.amt = 1;

With subselect into the FROM clause, the subselect query only needs to be run once.