2016-10-05 5 views
2

Проверьте следующий пример (Oracle синтаксис):SQL с неоднозначной колонкой

create table t1 (id number, a varchar2(255)); 
create table t2 (id number, a varchar2(255)); 
create table t3 (id number); 

select * from t1 where id in (select id from t2 where a = 'aa'); 
select * from t1 where id in (select id from t3 where a = 'aa'); 

Оба выбора работает хорошо, но они используют различные атрибуты для фильтрации. На мой взгляд, первый SQL должен дать ошибку, потому что столбец a неоднозначно определен. Это не определено в официальном стандарте SQL?

ответ

5

Это не ясное заявление, но the documentation does refer to this behaviour:

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

Поэтому в основном это говорит о том, что для вашего первого заявления ссылки t1.a вы должны явно использовать это имя (или псевдоним):

select * from t1 where id in (select id from t2 where t1.a = 'aa'); 

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

Но он также говорит, что безопаснее всегда явно в любом случае:

select * from t1 where t1.id in (select t2.id from t2 where t2.a = 'aa'); 

или

select * from t1 where t1.id in (select t2.id from t2 where t1.a = 'aa'); 

и для второго утверждения:

select * from t1 where t1.id in (select t3.id from t3 where t1.a = 'aa'); 
+0

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

+0

@Whisky_jb - Я согласен, что ошибка имеет смысл здесь, но это не то, что Oracle решил делать по любой причине. Такое поведение, вероятно, восходит к самым ранним дням, и я не знаю, как это изменить. –

+1

@AlexPoole: это поведение соответствует стандарту SQL. Oracle следовал стандарту здесь. –

-1

Первый SQL.

select * from t1 where id in (select id from t2 where a = 'aa'); 

Первый запрос будет принимать "a" столбец t2 таблицы во время выполнения запроса. Как известно, обе таблицы t1 и t2 имеют одинаковое имя столбца, но предпочтения заданы локальному столбцу.

Второй SQL.

select * from t1 where id in (select id from t3 where a = 'aa'); 

При выполнении второго запроса будет выбрать столбец "a" из таблицы t1.

Поскольку нет столбца с именем «a», и, следовательно, SQL будет принимать разные атрибуты для выполнения запроса.

+0

Я не повторяюсь, я просто объясняю. – Pirate

1

Поведение именно так и должно быть основано на многолетних принципах программирования. Я не видел стандарта SQL (видимо, его нельзя проверить бесплатно), но при программировании вообще «столкновение» между именами является одной из наиболее распространенных проблем, и по крайней мере для некоторых ситуаций существуют очень простые правила , Это один из них: локальное имя всегда будет маскировать то же имя, которое может существовать в вызывающей среде.

Печально то, что сам Oracle не всегда следует этому простому правилу. Есть некоторые ошибки, связанные с этим в факторизованных подзапросах (было некоторое обсуждение этого вопроса в OTN, в результате чего были поданы отчеты об ошибках в Oracle).

+0

Да, и мы открыли также SR для этого примера, но они просто закрывают его, как говорят его ОК. На мой взгляд, ORA-00918: столбец двусмысленно должен появиться, чтобы пользователи узнали об этой проблеме? Но может быть, я просто ошибаюсь? –

+0

Я имел в виду, что с предложением WITH Oracle не всегда сначала ищет локальные переменные (они не всегда маскируют одно и то же имя из вызывающей среды). Ваш пример явно не является ошибкой, поскольку поведение преднамеренно и документировано - см. Ответ Алекса. – mathguy

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