Запрос, в котором два столбца находятся в результате вложенного запроса - PullRequest
3 голосов
/ 26 января 2011

Я пишу запрос так:

select * from myTable where X in (select X from Y) and XX in (select X from Y)

Значения из столбцов X и XX должны быть результатом одного и того же запроса: select X from Y.

Я думаю, что этот запрос вызывается дважды, поэтому его бессмысленно. Могу ли я написать этот запрос более эффективно? Может быть, временная таблица?

Ответы [ 4 ]

4 голосов
/ 26 января 2011

На самом деле нет, нет более разумного способа написать это (не посещая Y дважды), учитывая, что X, которым соответствуют myTable.X и myTable.YY, может быть не из одной строки.

КакВ качестве альтернативы форма запроса EXISTS имеет вид

select *
from myTable A
where exists (select * from Y where A.X = Y.X)
  and exists (select * from Y where A.XX = Y.X)

. Если Y содержит значения X, равные 1,2,3,4,5, x.x = 2 и x.xx = 4, они оба существуют (для разных записей в Y), изапись из myTable должна быть показана в выходных данных.

РЕДАКТИРОВАТЬ: Этот ответ ранее заявил, что You could rewrite this using _EXISTS_ clauses which will work faster than _IN_.А.С. Мартин указал, что это не так (конечно, не для SQL Server 2005 и выше).Смотрите ссылки

1 голос
/ 26 января 2011

Вероятно, будет неэффективно пытаться написать этот запрос, ссылаясь только на Y один раз. Однако, учитывая, что вы используете SQL Server 2008, есть варианты, которые можно использовать:

Select ...
From MyTable As T
Where Exists    (
                Select 1
                From Y
                Where Y.X = T.X
                Intersect
                Select 1
                From Y
                Where Y.X = T.XX
                )

Добавление

На самом деле, я могу придумать, как вы могли бы сделать это, не используя Y более одного раза (ничего не было сказано об использовании MyTable более одного раза). Тем не менее, это больше по академическим причинам, так как я думаю, что использование моего первого решения, вероятно, будет работать лучше:

Select ...
From MyTable As T
Where Exists    (
                Select 1
                From Y
                Where Exists( 
                            Select 1 
                            From MyTable1 As T1 
                            Where T1.X = Y.X 
                            Intersect
                            Select 1 
                            From MyTable1 As T2 
                            Where T2.XX = Y.X
                            )
                    And Y.X In(T.X, T.XX)
                )
0 голосов
/ 26 января 2011

Не уверен, в чем проблема, но не просто ПРИСОЕДИНЯЙТЕСЬ к ответу?

SELECT t.* 
FROM myTable 
JOIN Y y1 ON y1.X = myTable.X
JOIN Y y2 ON y2.X = myTable.XX

или

SELECT t.*
FROM myTable, Y y1, Y y2
WHERE y1.X = myTable.X AND y2.X = myTable.XX

ДОБАВЛЕНО: если настоятельно необходимо исключить второй запрос для Y, давайте изменим логику:

;WITH A(X)
AS (
  -- this will select all values that can be found in Y and myTable X and XX fields.
  SELECT Y.X -- if there are a lot of dups, add DISTINCT
  FROM Y, myTable
  WHERE Y.X IN (myTable.X, myTableXX)
)
-- now join back to the orignal table and filter.
SELECT t.* 
FROM myTable
-- similar to what has been mentioned before 
WHERE EXISTS(SELECT TOP 1 * from A where A.X = myTable.X)
      AND EXISTS(SELECT TOP 1 * from A where A.X = myTable.XX)

Если вам не нравится WITH, вы можете использовать предложение SELECT INTO и создать таблицу в памяти.

0 голосов
/ 26 января 2011
WITH
   w_tmp AS(
      SELECT x
        FROM y
   )
SELECT * 
  FROM myTable
 WHERE x IN (SELECT x FROM w_tmp)
   AND xx IN (SELECT x FROM w_tmp)

(я читал это в документации Oracle, но я думаю, что MS тоже может сделать эту оптимизацию)
Таким образом, оптимизатор точно знает, что вы выполняете тот же запрос, и может создать временную таблицу для получения результатов (но оптимизатор должен решить, стоит ли это того. Для крошечных запросов затраты на создание временной таблицы могут быть слишком высокими).

Также (и на самом деле это гораздо важнее для меня), когда подзапрос состоит из 50 строк, human легче увидеть, что в обоих случаях используется одна и та же вещь. Очень похоже на разложение длинных функций на подпрограммы

Документы на MSDN

...