У меня есть 3 таблицы: Таблица1, Таблица2 и Таблица3. Три таблицы содержат 3 одинаковых столбца SAMECOL1, SAMECOL2 и SAMECOL3. Обе таблицы Table1 и Table2 имеют столбец MY_PK_COL, который является первичным ключом Table1.
Когда я использую этот запрос в SQL Developer, я получаю сообщение об ошибке:
SELECT * FROM Table1
INNER JOIN Table2 ON Table1.MY_PK_COL = Table2.MY_PK_COL
JOIN Table3 USING (SAMECOL1, SAMECOL2, SAMECOL3)
- 00000 - "столбец определен неоднозначно"
Но когда я использую это, все в порядке:
SELECT * FROM Table1
JOIN Table2 USING (MY_PK_COL, SAMECOL1, SAMECOL2, SAMECOL3)
JOIN Table3 USING (SAMECOL1, SAMECOL2, SAMECOL3)
Если я правильно понимаю, в первом запросе 3 столбца SAMECOLx переименовываются с такими псевдонимами, как SAMECOL1_1, SAMECOL2_1, SAMECOL3_1, поэтому это не должно быть проблемой для второго соединения с предложением USING (неоднозначная вещь).
Итак, в чем проблема с первым запросом?
Если я правильно понимаю, в первом запросе 3 столбца SAMECOLx переименовываются с такими псевдонимами, как SAMECOL1_1, SAMECOL2_1, SAMECOL3_1
Нет. Операция соединения не переименовывает столбцы. Если вы запросили только эти две таблицы с этим соединением, то ваш клиент выбирает добавление части _1
при отображении результатов; это не часть набора результатов.
То, что вы видите, зависит от вашего клиента и от того, как вы его запускаете. Например, SQL Developer изменит заголовки столбцов, как вы описываете в окне «Результат запроса», если вы запустите его как запрос (оператор запуска или управление-ввод); но если вы запустите его как скрипт (запустите скрипт или F5), то он не сделает этого в окне «Вывод скрипта». Как и SQL*Plus или SQLcl.
Итак, первая часть
Table1
INNER JOIN Table2 ON Table1.MY_PK_COL = Table2.MY_PK_COL
эффективно делает все столбцы из обеих таблиц доступными для последующей обработки, включая два столбца, которые все еще называются SAMECOL1
, а затем следующую часть
JOIN Table3 USING (SAMECOL1, SAMECOL2, SAMECOL3)
не знает, какой из двух столбцов вы имеете в виду - он не может различить Table1.SAMECOL1
и Table2.SAMECOL2
. Вы знаете, что это одни и те же данные, но в запросе нет ничего, что говорило бы об этом.
Во второй форме первый USING
устраняет эту двусмысленность:
Table1
JOIN Table2 USING (MY_PK_COL, SAMECOL1, SAMECOL2, SAMECOL3)
имеет только одну проекцию SAMECOL1
, которая как бы не из обеих исходных таблиц, а ни из одной из них.
Вы можете увидеть разницу в этой скрипте, которая не использует псевдонимы для повторяющихся столбцов в первом запросе, как вы предполагали (и как это делает ваш клиент):
SELECT * FROM Table1
INNER JOIN Table2 ON Table1.MY_PK_COL = Table2.MY_PK_COL
SELECT * FROM Table1
JOIN Table2 USING (MY_PK_COL, SAMECOL1, SAMECOL2, SAMECOL3)
Не используйте USING
ни для одного соединения, а замените второе соединение ON
правильно укажите условие — однако вы хотите выбрать, какое из них использовать.
Если вы используете только первое соединение, вы увидите очевидную разницу
SELECT * FROM Table1
JOIN Table2 USING (MY_PK_COL, SAMECOL1, SAMECOL2, SAMECOL3);
MY_PK_COL SAMECOL1 SAMECOL2 SAMECOL3
---------- ---------- ---------- ----------
1 1 1 1
SELECT * FROM Table1
INNER JOIN Table2 ON Table1.MY_PK_COL = Table2.MY_PK_COL;
MY_PK_COL SAMECOL1 SAMECOL2 SAMECOL3 MY_PK_COL SAMECOL1 SAMECOL2 SAMECOL3
---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
1 1 1 1 1 1 1 1
Итак, дело в том, что при использовании ON condition
select *
возвращает все столбцы из обеих таблиц, что приводит к вашей проблеме.
Соединение с USING column
возвращает используемые столбцы только один раз - к сожалению, я не могу найти документацию по этому поведению, самое близкое описание
Во внешнем объединении с предложением USING запрос возвращает один столбец, объединяющий два соответствующих столбца в объединении.
Однако это зависит от вашего клиента; если вы запустите версию ON
в SQL Developer как запрос (а не сценарий), то в окне результатов запроса он «услужливо» изменяет заголовки столбцов, поэтому вы видите SAMECOL1
и SAMECOL1_1
, как описано в OP. Что делает его более запутанным и менее очевидным.
Я хотел сказать, что синтаксис USING
возвращает используемые столбцы только один раз в запросе select *
, а объединение с ON
, наоборот, возвращает все столбцы из обеих таблиц. Я хотел указать на это ссылкой на документацию, которую, к сожалению, не могу найти @AlexPoole.
Да, я не согласен с этим, но ОП сбит с толку, потому что, когда они запускают этот запрос, они видят разные заголовки столбцов, поэтому он не выглядит двусмысленным — их клиент делает вид, что есть только один SAMECOL1
, который они затем пытаются использовать, но это не так. В вашем выводе это очевидно, а в их нет...
Спасибо очень понятный ответ! Но если у меня есть разные значения между столбцами SAMECOLx в таблице 1 и таблице 2, и я хочу выбрать один из них для сравнения с таблицей 3. Как я могу этого добиться?