Значения из нескольких таблиц в строке - PullRequest
2 голосов
/ 17 июля 2009

У меня есть следующие 3 таблицы

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

Теперь мне нужен запрос к table3, который должен сделать следующее:

Для отображения поля имени таблицы1 и таблицы2. Но моя проблема в том, что Если поле P на table3 истинно, я хочу, чтобы оно отображало имя поля таблицы2, где table2.id = table3.id, но если оно ложно, мне нужно прочитать имя поля имени table1, где table1.id = table3.id.

Программа, которая будет отображать результаты, является настольным приложением, и я мог бы сделать это с какой-то процедурой или чем-то другим, чтобы отобразить их, но было бы лучше, если бы у меня был SQL-запрос, чтобы сделать это для меня.

Ответы [ 5 ]

3 голосов
/ 17 июля 2009

Это:

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

, или это:

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

В системах, способных делать HASH JOIN (то есть Oracle, SQL Server, PostgreSQL, но не MySQL), второе лучше, если логические значения распределены равномерно, т.е. е. есть много как TRUE, так и FALSE, и если table3 достаточно велико.

Первый вариант лучше, если в распределении наблюдается перекос, если строк в table3 намного меньше, чем в table1 или table2, или если вы используете MySQL.

Обновление:

Если большинство полей имеют значение false, следующий запрос, вероятно, будет лучшим:

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

Подзапрос здесь будет использоваться только как запасной вариант и будет выполняться только для редких TRUE значений.

Обновление 2:

Я не могу проверить это в Firebird, но в большинстве систем синтаксис ORDER BY, как в запросе выше, будет работать. Если это не так, оберните запрос во встроенное представление:

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

, хотя это может снизить производительность (по крайней мере, в MySQL это так).

1 голос
/ 17 июля 2009

вы можете использовать

select if(P, t1.name, t2.name) ...
0 голосов
/ 24 ноября 2017

Это так же просто, как этот запрос в MySQL.

        SELECT T3.ID,
               T3.P,
               IF(T3.P = true,  T2.NAME, T1.NAME) AS NAME
        FROM Table3 T3
        LEFT JOIN Table2 T2 ON T2.ID = T3.ID
        LEFT JOIN Table1 T1 ON T1.ID = T3.ID
0 голосов
/ 17 июля 2009

Возможно, не вариант, но иногда редизайн схемы решит много проблем. Любое решение, которое выполняет функции для каждой строки, должно тщательно * быть тщательно проверено на предмет проблем с производительностью (на самом деле любой запрос должен постоянно отслеживаться на предмет проблем с производительностью, особенно на функции каждой строки). *

Рассмотрим объединение таблиц 1 и 2 таким образом:

Table1And2:
    Id | IsTable2 | Name
    ---+----------+-----
    1  | false    | X
    2  | false    | Y
    3  | false    | Z
    1  | true     | A
    2  | true     | B
    3  | true     | C
    Primary key (Id,IsTable2)
    Possible index on (IsTable2) as well, depending on DBMS.

Table3:
    Id | P (Boolean field)  | OtherCols
    ---+--------------------+----------
     1 | true               |
     2 | true               |
     1 | false              |

Тогда ваш запрос станет относительно простым (и почти наверняка ослепительно быстрым):

select a.Id, b.Name, a.OtherCols
from Table3 a, Table1And2 b
where a.Id = b.Id and a.P = b.isTable2

Проблема производительности обычно поднимает голову только для больших таблиц, с размерами мэйнфреймов, где 5 миллионов строк считаются таблицей конфигурации :-) Это может быть необязательно для того типа таблиц, с которыми вы имеете дело, но это полезный инструмент для иметь в арсенале.

0 голосов
/ 17 июля 2009
SELECT `id`, IF(`table3`.`P`, `table2`.`name`, `table1`.`name`) AS `name`
FROM `table3`
JOIN `table2` USING (`id`)
JOIN `table1` USING (`id`)
...