Sql Server查询语法

时间:2009-05-27 12:48:31

标签: sql mysql sql-server-2005

我需要执行这样的查询:

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

我知道我可以采取一种解决方法,但我想知道这种语法是否可行(我认为)在Mysql中。

5 个答案:

答案 0 :(得分:8)

您发布的查询将无法在sql server上运行,因为select子句中的子查询可能会返回多行。我不知道MySQL会如何对待它,但是从我正在阅读的内容中,如果子查询返回任何重复项,MySQL也会产生错误。我知道SQL Server甚至不会编译它。

区别在于MySQL至少会尝试运行查询,如果你非常幸运(Table2Id在Table1中是唯一的),它将会成功。更可能的是会返回错误。 SQL Server根本不会尝试运行它。

这是一个应该在任一系统上运行的查询,如果表1中的Table2Id不唯一,则不会导致错误。在这种情况下, 将返回“重复”行,其中唯一的区别是Table1.Column值的来源:

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

也许如果你分享了你想要实现的目标,我们可以帮助你编写一个查询来完成它。

答案 1 :(得分:2)

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 Server1中)

你究竟想做什么?

请提供一些示例数据和所需的结果集。

答案 2 :(得分:2)

我同意Joel的解决方案,但我想讨论为什么你的查询使用不好(即使语法基本上有效)。这是一个相关的子查询。这些问题的第一个问题是,如果子查询可能为记录返回多个值,则它们不起作用。第二个也是更关键的问题(在我看来)是他们必须逐行而不是数据集。这意味着它们几乎总会影响性能。因此,相关的子查询几乎不应该在生产系统中使用。在这个简单的例子中,Joel显示的连接是正确的解决方案。

如果子查询更复杂,您可能希望将其转换为派生表(这也会修复与记录问题关联的多个值)。虽然派生表看起来很像未经启动的相关子查询,但它不会以相同的方式执行,因为它作用于数据集而不是逐行,因此通常会明显更快。您实际上是将查询作为连接中的表格。

下面是您的查询重写为派生表的示例。 (当然在生产代码中你不会使用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

答案 3 :(得分:0)

这种语法基本上是有效的(你需要将where tmp=...移到外部“select * from(....)”,尽管它有两个名为“Table2”的模糊“ - 您应该至少在该表的一个用法中定义别名以消除歧义。

除非您打算从table1返回与table2中的列对应的列...在这种情况下,您可能只想加入表?

答案 4 :(得分:0)

你已经有了各种答案,其中一些比其他答案更有用。但要直接回答你的问题:

不,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 DBMS引擎 DOES 有一个扩展,允许使用NAMED关键字代替AS关键字,以及NAMED表达式< em> CAN 在QUERY中的其他位置引用,包括WHERE子句,GROUP BY子句和ORDER BY子句。 Shuh-weeeet