2015-02-02 4 views
4

Я столкнулся с каким-то странным поведением, которое мешает мне настраивать запрос так, как хотелось бы. По достоинству оценят любые идеи. Если какая-либо информация о таблицах будет полезна, сообщите мне. Я просмотрел их, и ничто не выскользнуло на меня, что могло бы вызвать это, но я не знал, что я искал. Вот поведение.Query throws ORA-00904 Недопустимый идентификатор при использовании объединений

Это прекрасно работает:

Select * 
From 
    SCHEMA_A.TABLE_A a, 
    SCHEMA_B.TABLE_B b, 
    SCHEMA_C.TABLE_C c, 
    SCHEMA_A.TABLE_D d 
Where 
    b.friend_id = c.friend_id 
    AND a.group_id = d.group_id 
    AND b.group_cd = d.group_cd 

Но это возвращает ORA-00904: b.friend_id = c.friend_id: неверный идентификатор

Select * 
From 
    SCHEMA_A.TABLE_A a, 
    SCHEMA_B.TABLE_B b, 
    SCHEMA_A.TABLE_D d 
Join 
    SCHEMA_C.TABLE_C c 
On 
    b.friend_id = c.friend_id 
Where 
    a.group_id = d.group_id 
    AND b.group_cd = d.group_cd 

Это возвращает ORA-00904: b.group_cd = d .group_cd: неверный идентификатор

Select * 
From 
    SCHEMA_A.TABLE_A a, 
    SCHEMA_B.TABLE_B b 
Join 
    SCHEMA_C.TABLE_C c 
On 
    b.friend_id = c.friend_id 
Join 
    SCHEMA_A.TABLE_D d 
On 
    a.group_id = d.group_id 
    AND b.group_cd = d.group_cd 

И это снова работает:

Select * 
From 
    SCHEMA_A.TABLE_A a, 
    SCHEMA_B.TABLE_B b 
Join 
    SCHEMA_C.TABLE_C c 
On 
    b.friend_id = c.friend_id 
Join 
    SCHEMA_A.TABLE_D d 
On 
    b.group_cd = d.group_cd 
Where 
    a.group_id = d.group_id 
+1

И поэтому вы не должны смешивать старые соединения типа Oracle с соответствующими ANSI, поскольку порядок соединения и область видимости становятся еще менее ясными ... придерживаться того или другого, предпочтительно ANSI * 8-) –

ответ

2

Try с using ключевым словом, которое предназначено для join на имени же колонке

Select * 
From 
    SCHEMA_A.TABLE_A a, 
    SCHEMA_B.TABLE_B b 
Join 
    SCHEMA_C.TABLE_C USING(friend_id) 
Join 
    SCHEMA_A.TABLE_D d using(group_id) 
where b.group_cd = d.group_cd; 

Также убедитесь, что вы выполняете другой запрос с нужными пользователями, как пользователь, который не имеет правильное разрешения бросит invalid identifier.

Edit: Реальная проблема заключается в том, что вы присоединяетесь TABLE_C с TABLE_D, но условие соединения относятся к TABLE_B изменению его

Select * 
From 
    SCHEMA_A.TABLE_A a, 
    SCHEMA_A.TABLE_D d, 
    SCHEMA_B.TABLE_B b 
Join 
    SCHEMA_C.TABLE_C c using(friend_id) 
Where 
    a.group_id = d.group_id 
    AND b.group_cd = d.group_cd; 

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

Для других людей, которые могут иметь ошибку invalid identifier, убедитесь, что ваша база данных не чувствительна к регистру, иначе обязательно используйте правильный футляр.

+0

He уже успешно работает код. Он ищет объяснение непоследовательного поведения. –

+0

Другая возможность - это чувствительность к регистру, но ваши оба вопроса записываются одинаково. –

+1

Это полностью. Я не понимал, что это работает, но теперь это имеет смысл. Спасибо! Fyi, я думаю, что проблема с ИСПОЛЬЗОВАНИЕМ заключалась в том, что она должна заменить ON, а не следовать ей – philfo

2

Я считаю, что вы столкнулись с сложностью в SQL, связанной с определением/приоритетом объединения. Поскольку я не являюсь программистом базы данных, я не могу сказать вам, почему он работает так, как он есть, но я вижу некоторую логику в том, как ведет себя парсер запросов.

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

Во втором запросе у вас есть сочетание кросс-соединений и внутренних соединений. Если предположить, что внутреннее соединение имеет приоритет над перекрестными объединениями, то таблицы c и d соединяются до того, как любые другие таблицы будут добавлены в микс. Поэтому, когда вы ссылаетесь на b.friend_id во внутреннем соединении, которое находится за пределами внутреннего соединения, анализатор запросов не может использовать этот столбец при оценке соединения.

В третьем запросе внутреннее соединение между таблицами b, c и d имеет приоритет над перекрестным соединением. Поэтому колонка a.group_id недоступна при оценке состояния внутреннего соединения. Когда вы берете таблицу из условия внутреннего соединения в конечном запросе, запрос больше не имеет противоречивого приоритета.

+0

Они не являются перекрестными соединениями; с использованием старого синтаксиса таблицы с разделителями-запятыми, Oracle использует условия 'where' в качестве условий соединения. (На самом деле он все еще может с присоединением ANSI, но это уже другая история). Но вы по-прежнему правы, C и D соединяются сначала, а B тогда не охвачен. –

+0

Фактически, список таблиц, разделенных запятыми, является подразумеваемым перекрестным соединением. См. Http://en.wikipedia.org/wiki/Join_%28SQL%29#Cross_join. Вот почему эта практика очень обескуражена для удобства чтения и производительности. – bluecollarcoder

+0

На той же странице: «Результаты перекрестного соединения могут быть отфильтрованы с помощью предложения WHERE, которое может затем произвести эквивалент внутреннего соединения». Я согласен, что это будет кросс-соединение без 'where', но поскольку есть одно, это внутреннее соединение, хотя терминология становится немного неудобной, когда вы используете термины ANSI для синтаксиса Oracle (даже [в документах] (http: //docs.oracle.com/cd/E11882_01/server.112/e41084/queries006.htm) * 8-) Я в основном расщепляю волосы. –

1

Проблема заключается в смешивании типов соединений. Когда вы используете таблицу, разделенную запятыми, в предложении FROM, каждый термин оценивается индивидуально. Рассмотрим следующий пример:

From 
    SCHEMA_A.TABLE_A a, 
    SCHEMA_B.TABLE_B b, 
    SCHEMA_A.TABLE_D d 
Join 
    SCHEMA_C.TABLE_C c 
On 
    b.friend_id = c.friend_id 

база данных пытается решить SCHEMA_A.TABLE_D d Join SCHEMA_C.TABLE_C c On b.friend_id = c.friend_id. В этой области b не имеет смысла (это отдельный термин).

Для вашей третьей версии я получаю "A"."GROUP_ID": invalid identifier, что также соответствует этому объяснению.

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

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