2008-09-12 2 views
4

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

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) имеет приоритет в двусмысленности. Я ошибаюсь, или просто не думаю об этой проблеме правильно?

Update:

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

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) ; 

Кто-нибудь есть ключ?

ответ

1

Боюсь, я не могу сказать вам, почему вы не получаете исключения, но я могу сказать, почему он выбрал версию КАТЕГОРИИ колонны над версией PARTS.

As far as I understood, in the case of left joins, the "main" table in the query (PARTS) has precedence in ambiguity

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

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

0

Как правило, рекомендуется в любом случае полностью определять все имена столбцов, так как это экономит оптимизатор. Конечно, в SQL Server.

Из того, что я могу получить из Oracle docs, кажется, что он будет только бросать, если вы выберете имя столбца дважды в списке выбора или один раз в списке выбора, а затем снова в другом месте, как предложение order by.

Возможно, вы раскрыли 'недокументированные функции' :)

2

Интересный сервер SQL, который выдает ошибку (как это необходимо)

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

Сервер: Msg 209, Level 16, State 1, Строка 1 Неоднозначное название столбца 'id'.

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

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

6

Here's the query (simplified version)

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

Какую версию оракул вы используете? 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: колонка двусмысленно определенный

1

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

0

Как и в HollyStyles, я не могу найти что-либо в документах Oracle, которые могут объяснить, что вы видите.

PostgreSQL, DB2, MySQL и MSSQL отказываются запускать первый запрос, поскольку он неоднозначен.

2

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

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

Явным образом определяя столбец как из PARTS (т.е. с левой стороны), вы получите ненулевое значение, предполагая, что поле имеет данные в PARTS.

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

+0

Я понимаю ваш ответ. Но почему я не получил ошибку двусмысленности в первую очередь? – Ovesh 2008-09-12 13:45:05

0

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

2

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

(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, чтобы получить подробную информацию о выполнении запроса, который показал что-то интересное. План в основном заключается в внешнем соединении PARTS и CATEGORIES, проект, который устанавливает результат, затем внешний соединяет его с SECTIONS. Интересная часть состоит в том, что в проекции первого внешнего соединения он включает только PTNO и SECCD - он НЕ включает CATCD из любой из первых двух таблиц. Поэтому конечным результатом является получение CATCD из третьей таблицы.

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

0

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

1

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

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

0

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

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

Смежные вопросы