Sql Server запрос синтаксиса - PullRequest
0 голосов
/ 27 мая 2009

Мне нужно выполнить запрос, подобный этому:

SELECT *, 
    (SELECT Table1.Column 
     FROM Table1 
     INNER JOIN Table2 ON Table1.Table2Id = Table2.Id 
    ) as tmp 
FROM Table2 WHERE tmp = 1

Я знаю, что могу обойти эту проблему, но я хотел бы знать, возможен ли этот синтаксис в том виде, в каком он (я думаю) в Mysql.

Ответы [ 5 ]

8 голосов
/ 27 мая 2009

Отправленный вами запрос не будет работать на сервере sql, поскольку подзапрос в предложении select может возвращать более одной строки. Я не знаю, как MySQL будет относиться к этому, но из того, что я читаю, MySQL также выдаст ошибку, если подзапрос вернет дубликаты. Я знаю, что SQL Server даже не скомпилирует его.

Разница в том, что MySQL, по крайней мере, попытается выполнить запрос, и, если вам очень повезет (Table2Id уникален в Table1), он выполнится успешно. Скорее всего, вернет ошибку. SQL Server вообще не будет пытаться запустить его.

Вот запрос, который должен выполняться в любой системе и не вызовет ошибку, если Table2Id не уникален в Table1. Он будет возвращать «дубликаты» строк в том случае, когда единственным отличием является источник значения Table1.Column:

SELECT  Table2.*, Table1.Column AS tmp
FROM Table1 
INNER JOIN Table2 ON Table1.Table2Id = Table2.Id
WHERE Table1.Column = 1

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

2 голосов
/ 27 мая 2009

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

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

Ниже приведен пример вашего запроса, переписанного как производная таблица. (Конечно, в рабочем коде вы не будете использовать select *, особенно в соединении, укажите нужные поля)

SELECT *     
FROM Table2 t2
JOIN
(SELECT Table1.[Column], Table1.Table2Id  as tmp      
FROM Table1      
INNER JOIN Table2 ON Table1.Table2Id = Table2.Id     ) as t
ON t.Table2Id = Table2.Id
WHERE tmp = 1
2 голосов
/ 27 мая 2009
SELECT  *
FROM    (
        SELECT  t.*,
                (
                SELECT  Table1.Column
                FROM    Table1
                INNER JOIN
                        Table2
                ON      Table1.Table2Id = Table2.Id
                ) as tmp
        FROM    Table2 t
        ) q
WHERE   tmp = 1

Это допустимый синтаксис, но он потерпит неудачу (как в MySQL, так и в SQL Server), если подзапрос вернет более 1 строку

Что именно вы пытаетесь сделать?

Пожалуйста, предоставьте пример данных и желаемый набор результатов.

0 голосов
/ 28 мая 2009

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

Нет, SQL Server не позволит вам ссылаться на псевдоним столбца (определенный в списке выбора) в предикате (предложение WHERE). Я думаю, что этого достаточно, чтобы ответить на вопрос, который вы задали.

Дополнительные детали:

(это обсуждение выходит за рамки исходного вопроса, который вы задали.)

Как вы заметили, есть несколько доступных обходных путей.

Наиболее проблематичным с отправленным вами запросом (как уже отмечали другие) является то, что мы не гарантируем, что подзапрос в списке SELECT вернет только одну строку. Если он возвращает более одной строки, SQL Server выдаст исключение «слишком много строк»:

 
    Subquery returned more than 1 value.
     This is not permitted when the subquery
     follows =, !=, , >= or when the
     subquery is used as an expression.

Для следующего обсуждения я собираюсь предположить, что проблема уже достаточно решена.

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

SELECT v.*
  FROM ( SELECT * 
              , (SELECT Table1.Column 
                   FROM Table1 
                   JOIN Table2 ON Table1.Table2Id = Table2.Id
                  WHERE Table1.Column = 1
                ) as tmp 
           FROM Table2
       ) v   
 WHERE v.tmp = 1

Обратите внимание, что SQL Server не будет вставлять предикат для внешнего запроса (WHERE v.tmp = 1) в подзапрос во встроенном представлении. Так что вам нужно добавить это в себя, включив предикат WHERE Table1.Column = 1 в подзапрос, особенно если вы зависите от этого, чтобы подзапрос возвращал только одно значение.

Это только один подход к решению проблемы, есть и другие. Я подозреваю, что план запроса для этого запроса SQL Server не будет оптимальным, для производительности вы, вероятно, захотите использовать предикат JOIN или EXISTS.

ПРИМЕЧАНИЕ: я не эксперт по использованию MySQL. Я не очень знаком с поддержкой MySQL для подзапросов. Я знаю (из мучительного опыта), что подзапросы не поддерживались в MySQL 3.23, что делало перенос приложений с Oracle 8 на MySQL 3.23 особенно болезненным.

Да и между прочим ... не представляет интереса для кого-либо, в частности, движок СУБД Teradata DOES имеет расширение, которое допускает использование ключевого слова NAMED вместо ключевого слова AS и выражения NAMED * 1031 На * CAN можно ссылаться в другом месте в QUERY, включая предложение WHERE, предложение GROUP BY и предложение ORDER BY. Shuh-weeeet

0 голосов
/ 27 мая 2009

Синтаксис такого типа в основном действителен (вам нужно переместить where tmp=... во внешнее «select * from (....)», хотя), хотя это неоднозначно, поскольку у вас есть два набора с именем «Table2» - вам, вероятно, следует определить псевдонимы хотя бы для одного из ваших использований этой таблицы, чтобы устранить неоднозначность.

Если вы не намеревались возвращать столбец из таблицы1, соответствующий столбцам в таблице2 ... в этом случае вы могли бы просто захотеть объединить таблицы?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...