Aldo Aldo - 2 months ago 14
SQL Question

Values from multiple tables on a row

I have the following 3 tables

Table1

ID | NAME
-----------
1 | X
2 | Y
3 | Z


Table2

ID | NAME
-----------
1 | A
2 | B
3 | C

Table3
ID | P (Boolean field) | Other cols
1 | True ...
2 | True....
1 | False


Now I need a query on table3 that has to do the following:

To display the name field of table1 and table2. But my problem is that
if field P on table3 is true I want it to display the name of table2's field where table2.id = table3.id but if it is false I need it to read the name of table1's name field where table1.id = table3.id.

The program which will display the results is a desktop application and i could do it with some procedure or something to display them, but would be nicer if I had a SQL query to do this for me.

Answer

This:

SELECT  CASE WHEN p
        THEN
        (
        SELECT  name
        FROM    table2 t2
        WHERE   t2.id = t3.id
        ) 
        ELSE
        (
        SELECT  name
        FROM    table1 t1
        WHERE   t1.id = t3.id
        )
        END
FROM    table3 t3

, or this:

SELECT  CASE WHEN p THEN t2.name ELSE t1.name END
FROM    table3 t3
JOIN    table1 t1
ON      t1.id = t3.id
JOIN    table1 t2
ON      t2.id = t3.id

In systems capable of doing HASH JOIN (that is Oracle, SQL Server, PostgreSQL, but not MySQL), the second one is better if the boolean values are distributed evenly, i. e. there are lots of both TRUE's and FALSE's, and if table3 is quite large.

The first one is better if there is a skew in distribution, if there are much fewer rows in table3 then in table1 or table2, or if you are using MySQL.

Update:

If the majority of fields are false, the following query will probably be the best:

SELECT  CASE WHEN p THEN
        (
        SELECT  name
        FROM    table2 t2
        WHERE   t2.id = t3.id
        )
        ELSE t1.name
        END AS cname
FROM    table3 t3
JOIN    table1 t1
ON      t1.id = t3.id
ORDER BY
        cname

Subquery here will only be used as a fallback, and will be executed only for the rare TRUE values.

Update 2:

I can't check it on Firebird, but on most systems the ORDER BY syntax as in query above will work. If it does not, wrap the query into an inline view:

SELECT  cname
FROM    (
        SELECT  CASE WHEN p THEN
                (
                SELECT  name
                FROM    table2 t2
                WHERE   t2.id = t3.id
                )
                ELSE t1.name
                END AS cname
        FROM    table3 t3
        JOIN    table1 t1
        ON      t1.id = t3.id
        ) q
ORDER BY
        cname

, though it may hamper performance (at least in MySQL it does).

Comments