SQL - псевдоним таблицы - PullRequest
       22

SQL - псевдоним таблицы

3 голосов
/ 09 октября 2008

Я только что научился (вчера) использовать «существует» вместо «в».

 BAD
 select * from table where nameid in ( 
          select nameid from othertable where otherdesc =  'SomeDesc' )      
 GOOD
 select * from table t where exists ( 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeDesc' )      

И у меня есть несколько вопросов по этому поводу:

1) Объяснение, как я понял, было: «Причина, по которой это лучше, заключается в том, что вместо построения массивного списка возможных результатов будут возвращаться только совпадающие значения» . Означает ли это, что хотя первый подзапрос может вернуть 900 результатов, второй вернет только 1 (да или нет)?

2) В прошлом мне приходилось жаловаться на СУБД: «можно извлечь только первые 1000 строк», этот второй подход решит эту проблему?

3) Какова область псевдонима во втором подзапросе? ... псевдоним существует только в скобках?

например

 select * from table t where exists ( 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeDesc' )      
 AND 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeOtherDesc' )      

То есть, если я использую тот же псевдоним (o для таблицы othertable) Во втором «существовать», будет ли возникать проблема с первым существующим? или они полностью независимы?

Это что-то, что связано только с Oracle, или оно действительно для большинства СУБД?

Большое спасибо

Ответы [ 5 ]

4 голосов
/ 09 октября 2008

Это специфично для каждой СУБД и зависит от оптимизатора запросов. Некоторые оптимизаторы обнаруживают предложение IN и переводят его.

Во всех протестированных СУБД псевдоним действителен только внутри ()

Кстати, вы можете переписать запрос как:

select t.* 
from table t 
join othertable o on t.nameid = o.nameid 
    and o.otherdesc in ('SomeDesc','SomeOtherDesc');

И, чтобы ответить на ваши вопросы:

  1. Да
  2. Да
  3. Да
3 голосов
/ 10 октября 2008

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

В вашем начальном запросе IN нотация будет действительной независимо от того, содержит ли OtherTable столбец NameID (и, действительно, существует ли OtherDesc в виде столбца в таблице или OtherTable - что непонятно ни в одном из ваших примеров, но предположительно столбец OtherTable). Именно это поведение делает коррелированный подзапрос в коррелированный подзапрос. Это также обычный источник беспокойства для людей, когда они впервые сталкиваются с ним - неизменно случайно. Поскольку стандарт SQL предписывает поведение интерпретации имени в подзапросе как обращения к столбцу во внешнем запросе, если в таблицах, упомянутых в подзапросе, нет столбца с соответствующим именем, но имеется столбец с соответствующее имя в таблицах, упомянутых во внешнем (главном) запросе, ни один продукт, который хочет заявить о соответствии (этой части) стандарта SQL, не сделает ничего другого.

Ответом на ваш вопрос Q1 является «это зависит», но с учетом вероятных предположений (NameID существует в виде столбца в обеих таблицах; OtherDesc существует только в OtherTable), результаты должны быть одинаковыми с точки зрения возвращенного набора данных, но не может быть эквивалентным с точки зрения производительности.

Ответ на ваш вопрос Q2 заключается в том, что в прошлом вы использовали низшую, если не дефектную СУБД. Если он поддерживает EXISTS, то СУБД может по-прежнему жаловаться на количество результатов.

Ответ на ваш Q3 применительно к первому запросу EXISTS: «t доступен в качестве псевдонима для всего оператора, но o доступен только в качестве псевдонима в скобках». Применительно к вашему второму примерному блоку - с AND, соединяющим два вложенных элемента выбора (второй из которых пропускает открытые скобки, когда я смотрю на него), тогда «t доступен в качестве псевдонима во всем утверждении и ссылается на тот же таблица, но есть два разных псевдонима, оба помечены как 'o', по одному для каждого подзапроса ". Обратите внимание, что запрос может не возвращать данные, если OtherDesc уникален для данного значения NameID в OtherTable; в противном случае для него требуется две строки в OtherTable с одинаковым NameID и два значения OtherDesc для каждой строки в таблице с этим значением NameID.

2 голосов
/ 09 октября 2008
  1. Специфично для Oracle: когда вы пишете запрос с использованием предложения IN, вы сообщаете оптимизатору на основе правил, что внутренний запрос должен запускать внешний запрос. Когда вы пишете EXISTS в предложении where, вы сообщаете оптимизатору, что вы хотите, чтобы внешний запрос выполнялся первым, используя каждое значение для извлечения значения из внутреннего запроса. См. «Разница между IN и EXISTS в подзапросах» .
  2. Возможно.
  3. Псевдоним, объявленный внутри подзапроса, живет внутри подзапроса. Кстати, я не думаю, что ваш пример с 2 подзапросами ANDed является допустимым SQL. Вы имели в виду UNION вместо AND?
1 голос
/ 21 августа 2013

Трудно обобщить, что EXISTS всегда лучше, чем IN. Логично, что в этом случае сообщество SQL заменило бы IN на EXISTS ... Кроме того, обратите внимание, что IN и EXISTS не одинаковы, результаты могут отличаться при использовании двух ...

С IN, обычно это полное сканирование внутренней таблицы один раз без удаления NULL (поэтому, если у вас есть NULL во внутренней таблице, IN не будет удалять NULLS по умолчанию) ... Хотя EXISTS удаляет NULL и в случае коррелированный подзапрос, он запускает внутренний запрос для каждой строки из внешнего запроса.

Предполагая, что нет NULL и это простой запрос (без корреляции), EXIST может работать лучше, если строка, которую вы находите, не является последней строкой. Если это последняя строка, возможно, EXISTS нужно сканировать до конца, как IN ... так что производительность похожа ...

Но IN и EXISTS не взаимозаменяемы ...

1 голос
/ 09 октября 2008

Лично я бы использовал для этого соединение, а не подзапрос.

SELECT t.*
FROM yourTable t
    INNER JOIN otherTable ot
        ON (t.nameid = ot.nameid AND ot.otherdesc = 'SomeDesc')
...