Неопределенность в левом соединении (только оракул?) - PullRequest
4 голосов
/ 12 сентября 2008

Мой босс обнаружил ошибку в запросе, который я создал, и я не понимаю причину ошибки, хотя результаты запроса подтверждают, что он правильный. Вот запрос (упрощенная версия) перед исправлением:

select PTNO,PTNM,CATCD
from PARTS 
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD); 

и вот оно после исправления:

select PTNO,PTNM,PARTS.CATCD
from PARTS 
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD); 

Ошибка заключалась в том, что для столбца CATCD отображались нулевые значения, то есть результаты запроса включали результаты из таблицы CATEGORIES вместо PARTS. Вот что я не понимаю: если в исходном запросе была неоднозначность, почему Oracle не выдал ошибку? Насколько я понял, в случае левых объединений «главная» таблица в запросе (PARTS) имеет приоритет в неоднозначности. Я не прав или просто не думаю об этой проблеме правильно?

Обновление:

Вот пересмотренный пример, где ошибка неоднозначности не выдается:

CREATE TABLE PARTS (PTNO NUMBER, CATCD NUMBER, SECCD NUMBER);

CREATE TABLE CATEGORIES(CATCD NUMBER);

CREATE TABLE SECTIONS(SECCD NUMBER, CATCD NUMBER);


select PTNO,CATCD 
from PARTS 
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD) 
left join SECTIONS on (SECTIONS.SECCD=PARTS.SECCD) ;

У кого-нибудь есть подсказка?

Ответы [ 12 ]

6 голосов
/ 12 сентября 2008

Вот запрос (упрощенная версия)

Я думаю, что путем упрощения запроса вы устранили реальную причину ошибки: -)

Какую версию оракула вы используете? Oracle 10g (10.2.0.1.0) дает:

create table parts (ptno number , ptnm number , catcd number);  
create table CATEGORIES (catcd number);

select PTNO,PTNM,CATCD from PARTS  
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD);

Я получаю ORA-00918: столбец двусмысленно определен

2 голосов
/ 15 сентября 2008

Это может быть ошибка в оптимизаторе Oracle. Я могу воспроизвести такое же поведение в запросе с 3 таблицами. Интуитивно кажется, что это должно привести к ошибке. Если я перезапишу его одним из следующих способов, он выдаст ошибку:

(1) Использование внешнего соединения в старом стиле

select ptno, catcd
from parts, categories, sections
where categories.catcd (+) = parts.catcd
  and sections.seccd (+) = parts.seccd

(2) Явная изоляция двух соединений

select ptno, catcd
from (
  select ptno, seccd, catcd
  from parts
  left join categories on (categories.CATCD=parts.CATCD) 
)
left join sections on (sections.SECCD=parts.SECCD)

Я использовал DBMS_XPLAN, чтобы получить подробную информацию о выполнении запроса, который показал кое-что интересное. План в основном состоит в том, чтобы внешнее объединение ЧАСТЕЙ и КАТЕГОРИЙ, проектирование этого набора результатов, а затем внешнее объединение его в РАЗДЕЛЫ. Интересная часть заключается в том, что в проекции первого внешнего соединения он включает только PTNO и SECCD - он НЕ включает CATCD из одной из первых двух таблиц. Поэтому окончательный результат - получение CATCD из третьей таблицы.

Но я не знаю, является ли это причиной или следствием.

2 голосов
/ 12 сентября 2008

По моему опыту, если вы создадите запрос, подобный этому, результат данных будет вытягивать CATCD с правой стороны объединения, а не слева, когда есть такое перекрытие полей.

Таким образом, так как в этом объединении будут все записи из ЧАСТЕЙ, и только некоторые из них будут извлечены из КАТЕГОРИЙ, вы будете иметь значение NULL в поле CATCD каждый раз, когда справа нет данных.

Путем явного определения столбца как ЧАСТИ (т. Е. С левой стороны) вы получите ненулевое значение, предполагая, что поле содержит данные в ЧАСТИ.

Помните, что с LEFT JOIN вам гарантированы данные только в полях левой таблицы, справа могут быть пустые столбцы.

2 голосов
/ 12 сентября 2008

Интересен SQL-сервер, который выдает ошибку (как и должно быть)

select id
from sysobjects s
left join syscolumns c on s.id = c.id

Сервер: сообщение 209, уровень 16, состояние 1, строка 1 Неоднозначное имя столбца 'id'.

select id
from sysobjects 
left join syscolumns  on sysobjects.id = syscolumns.id

Сервер: Msg 209, Уровень 16, Состояние 1, Линия 1 Неоднозначное имя столбца 'id'.

1 голос
/ 18 сентября 2008

Это известная ошибка в некоторых версиях Oracle при использовании объединений в стиле ANSI. Правильным поведением было бы получение ошибки ORA-00918.

Всегда лучше указывать имена таблиц; таким образом ваши запросы не прерываются, когда вы добавляете новый столбец с именем, которое также используется в другой таблице.

1 голос
/ 12 сентября 2008

Боюсь, я не могу сказать вам, почему вы не получаете исключение, но я могу постулировать, почему он выбрал версию колонки CATEGORIES вместо версии PARTS.

Насколько я понял, в случае левых объединений "главная" таблица в запросе (PARTS) имеет приоритет в двусмысленности

Непонятно, под "основной" вы подразумеваете просто левую таблицу в левом соединении или "ведущую" таблицу, как вы видите концептуально запрос ... Но в любом случае, то, что вы видите как "главное" "таблица в запросе, как вы ее написали, не обязательно будет" основной "таблицей при фактическом выполнении этого запроса.

Я предполагаю, что Oracle просто использует столбец из первой таблицы, к которой он обращается, при выполнении запроса. А поскольку для большинства отдельных операций в SQL не требуется, чтобы одна таблица обрабатывалась раньше другой, во время анализа СУБД примет решение, какая из них наиболее эффективна для сканирования в первую очередь. Попробуйте получить план выполнения запроса. Я подозреваю, что это может показать, что сначала он попадает в КАТЕГОРИИ, а затем в ЧАСТИ.

1 голос
/ 12 сентября 2008

Я использую Oracle 9.2.0.8.0. и он выдает ошибку «ORA-00918: столбец определен неоднозначно».

0 голосов
/ 11 августа 2011

Это ошибка в Oracle 9i. Если вы объединяете более 2 таблиц с использованием нотации ANSI, он не обнаружит неоднозначности в именах столбцов и может вернуть неправильный столбец, если псевдоним не используется.

Как уже упоминалось, он исправлен в 10g, поэтому, если псевдоним не используется, будет возвращена ошибка.

0 голосов
/ 17 сентября 2008

Большой вопрос, который вы должны задать себе: почему у меня есть код категории в таблице деталей, которой нет в таблице категорий?

0 голосов
/ 12 сентября 2008

@ Пат: Я получаю ту же ошибку здесь для вашего запроса. Мой запрос немного сложнее, чем я первоначально разместил. Сейчас я работаю над простым воспроизводимым примером.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...