У меня есть 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 (неоднозначная вещь).
Итак, в чем проблема с первым запросом?
🤔 А знаете ли вы, что...
SQL поддерживает создание представлений (VIEW), что позволяет абстрагироваться от структуры таблицы при выполнении запросов.
Если я правильно понимаю, в первом запросе 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)
Если вы используете только первое соединение, вы увидите очевидную разницу
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 запрос возвращает один столбец, объединяющий два соответствующих столбца в объединении.