我需要执行这样的查询:
SELECT *,
(SELECT Table1.Column
FROM Table1
INNER JOIN Table2 ON Table1.Table2Id = Table2.Id
) as tmp
FROM Table2 WHERE tmp = 1
我知道我可以采取一种解决方法,但我想知道这种语法是否可行(我认为)在Mysql中。
答案 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 Server
和1
中)
你究竟想做什么?
请提供一些示例数据和所需的结果集。
答案 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