select语句列中的MYSQL子查询

Dan*_*and 6 mysql subquery

select(投影)的列字段中的子查询如何与主查询的结果配对?形式:

 SELECT id,email,(SELECT name From Names WHERE Names.id=Users.id) as name
 FROM Users
Run Code Online (Sandbox Code Playgroud)

子查询是从 , 的输出中每行执行一次SELECT id,email FROM Users,因此应该LIMIT 1在子查询上使用(因为子查询中只有 1 行可以与主查询中的一行配对),还是子查询运行一次,并且然后每个结果都与来自 的相应行配对SELECT id,email FROM Users,很像等效连接:SELECT id,email,name FROM Users JOIN Names ON Users.id=Names.id

a_v*_*lad 7

在理想情况下,当 Names.id = Users.id 只返回 1 条记录时,两个查询相同

当它不正确时的区别。

SELECT id,email,(SELECT name From Names WHERE Names.id=Users.id) as name
 FROM Users
Run Code Online (Sandbox Code Playgroud)

将停止工作并返回错误,因此您需要添加 LIMIT 类

SELECT id,email,(SELECT name From Names WHERE Names.id=Users.id ORDER BY something LIMIT 1) as name
 FROM Users
Run Code Online (Sandbox Code Playgroud)

同时查询

SELECT id,email,name FROM Users JOIN Names ON Users.id=Names.id
Run Code Online (Sandbox Code Playgroud)

继续工作而没有错误,此查询返回与用户相关的名称中的所有行

在其他一些情况下,当您只期望 1 个名称时,您将需要添加 GROUP BY 条件

SELECT id,email,name FROM Users JOIN Names ON Users.id=Names.id GROUP BY Users.id
Run Code Online (Sandbox Code Playgroud)

但是这种情况可能会从 Names 返回不可预测的名称(并且它不是 100% 的 SQL 合法构造),并且您再次需要使用派生表再添加 1 级 JOIN,并且有时它可能是丑陋的构造,

所以,你总是可以比较哪种形式的查询更适合所选案例,简单的例子:

SELECT t1.id,t1.email,t2.name FROM Users t1 JOIN 
(SELECT id, name FROM Names n1 INNER JOIN 
(SELECT MAX(dateregistered) as dateregistered, id FROM Names GROUP BY id) n2 ON n1.id=n2.id AND n1.dateregistered=n2.dateregistered) t2
ON t1.id = t2.id
Run Code Online (Sandbox Code Playgroud)

将返回与以下相同的结果:

SELECT id,email,(SELECT name From Names WHERE Names.id=Users.id ORDER BY dateregistered DESC LIMIT 1) as name
FROM Users
Run Code Online (Sandbox Code Playgroud)

添加:带有名称的示例看起来不现实,但实际情况 - 当您需要请求的不是名称(实际上是每人 1 个),而是具有 10 年历史的客户的实际邮政地址时。他可以有20个地址,你最需要回馈


Dar*_*byM 0

根据我的经验,是的,您的子查询将为外部查询的每一行运行。

此外,由于您在子查询中没有使用任何形式的分组/聚合,因此无法保证查询将返回哪一行。

另一方面,查询最好这样写:

SELECT u.id,u.email,n.name
FROM Users u
JOIN Names n
    ON n.id = u.id
Run Code Online (Sandbox Code Playgroud)

如下所述,如果表用户和表名称不保持真正的一对一关系。用户中的一行可能在名称中具有相同 id 的多行。如果是这种情况,您可以对查询进行以下更改来解决此问题。

SELECT u.id,u.email,n.name
FROM Users u
RIGHT JOIN Names n
    ON n.id = u.id
WHERE u.id IS NOT NULL
LIMIT 1
Run Code Online (Sandbox Code Playgroud)

这将产生 Users 表中的每一行,这些行在 Names 表中拥有匹配的 id。但将响应限制为 1。请记住,如果没有 LIMIT 1,如果由于某种原因 Names 表中的多个条目具有相同的 id,这将列出重复的 u.emails。

  • 分组/聚合不保证哪一行将通过“LIMIT 1”传送。您需要“ORDER BY”来获得这样的保证。 (2认同)