MySQL的子查询中FROM和EXISTS子句的使用教程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL的子查询中FROM和EXISTS子句的使用教程相关的知识,希望对你有一定的参考价值。

参考技术A FROM
子查询
FROM
子句中的子查询
mysql
FROM
子查询是指
FROM
的子句作为子查询语句,主查询再到子查询结果中获取需要的数据。FROM
子查询语法如下:
SELECT
...
FROM
(subquery)
AS
name
...
子查询会生成一个临时表,由于
FROM
子句中的每个表必须有一个名称,因此
AS
name
是必须的。FROM
子查询也称为衍生数据表子查询。
FROM
子查询实例
table1:
s1
s2
1
5
2
12
3
20
FROM
子查询
SQL
如下:
SELECT
s1,s2
FROM
(SELECT
s1,
s2*2
AS
s2
FROM
table1)
AS
temp
WHERE
s1
>
1
查询返回结果如下所示:
s1
s2
2
24
3
40
提示
MySQL
FROM
子句中的子查询可以返回标量、列、行或表,但不能为有关联的子查询。
MySQL
子查询
EXISTS

NOT
EXISTS
MySQL
EXISTS

NOT
EXISTS
子查询
MySQL
EXISTS

NOT
EXISTS
子查询语法如下:
SELECT
...
FROM
table
WHERE
EXISTS
(subquery)
该语法可以理解为:将主查询的数据,放到子查询中做条件验证,根据验证结果(TRUE

FALSE)来决定主查询的数据结果是否得以保留。
MySQL
EXISTS
子查询实例
下面以实际的例子来理解
EXISTS
子查询。下面是原始的数据表:
article
文章表:
user
用户表:
我们要查出
article
表中的数据,但要求
uid
必须在
user
表中存在。SQL
语句如下:
SELECT
*
FROM
article
WHERE
EXISTS
(SELECT
*
FROM
user
WHERE
article.uid
=
user.uid)
返回查询结果如下:
从语句执行结果可以看出,article
表中第
4
条记录没有被保留,原因就是该条记录的数据在子查询中返回的结果是
FALSE

当上面的
SQL
使用
NOT
EXISTS
时,查询的结果就是
article
表中
uid
不存在于
user
表中的数据记录。
提示
EXISTS
(subquery)
只返回
TRUE

FALSE,因此子查询中的
SELECT
*
也可以是
SELECT
1
或其他,官方说法是实际执行时会忽略
SELECT
清单,因此没有区别。
EXISTS
子查询的实际执行过程可能经过了优化而不是我们理解上的逐条对比,如果担忧效率问题,可进行实际检验以确定是否有效率问题。
EXISTS
子查询往往也可以用条件表达式、其他子查询或者
JOIN
来替代,何种最优需要具体问题具体分析。

MYSQL 获取最低值的记录 | View 的 SELECT 包含 FROM 子句中的子查询

【中文标题】MYSQL 获取最低值的记录 | View 的 SELECT 包含 FROM 子句中的子查询【英文标题】:MYSQL Get record with lowest value | View's SELECT contains a subquery in the FROM clause 【发布时间】:2013-03-09 11:38:24 【问题描述】:

我一直在处理这个查询,这让我抓狂。

我有一个产品表和一个包含子产品的表。 简而言之,我想用产品数据和子产品的最低(折扣)价格创建一个视图。 (想想一件衬衫,有几个子产品(颜色/尺寸)等)

其次,我想在 VIEW 中使用这个查询,这部分让我抓狂。

我现在的查询:

  SELECT m.* from product_items m join
  (select product_id, min(price_discount) md 
       from product_items group by product_id) mm
  on m.product_id=mm.product_id and m.price_discount=md

这个查询正在运行,我得到了很好的结果。但现在我想创建一个视图(vw_product_lowest)。 然后报错:ERROR 1349 (HY000): View's SELECT contains a subquery in the FROM clause

谁能帮我将该查询转换为兼容的 VIEW 查询?谢谢!

【问题讨论】:

【参考方案1】:

你有几个选择:

    将子查询放入视图中(可能会很慢,因为结果视图没有可用于执行后续连接的索引):

    CREATE VIEW mm AS
      SELECT   product_id, MIN(price_discount) price_discount
      FROM     product_items
      GROUP BY product_id
    ;
    
    CREATE VIEW my_view AS
      SELECT * FROM product_items m NATURAL JOIN mm
    ;
    

    使用correlated subquery(也可能很慢,因为必须为表中的每条记录评估子查询 - 使用(product_id, price_discount) 上的复合索引可以获得最佳性能):

    CREATE VIEW my_view AS
      SELECT * FROM product_items m WHERE price_discount = (
        SELECT MIN(mm.price_discount)
        FROM   product_items mm
        WHERE  mm.product_id = m.product_id
      )
    ;
    

    优化相关子查询using the EXISTS strategy(也将受益于(product_id, price_discount) 上的复合索引):

    CREATE VIEW my_view AS
      SELECT * FROM product_items m WHERE NOT EXISTS (
        SELECT 1
        FROM   product_items mm
        WHERE  mm.product_id     = m.product_id
           AND mm.price_discount < m.price_discount
        LIMIT  1
      )
    ;
    

【讨论】:

哇。谢谢您的回答。虽然我确实使用了其他答案,但我会调查它。就速度/优化而言,另一个答案对我来说似乎更好。【参考方案2】:

根据手册,VIEW 不能包含子查询。如果你真的想在你的查询上创建一个VIEW,你需要为你的子查询创建一个单独的视图,例如

第一个视图

CREATE VIEW MinimumPrice
AS 
SELECT  product_id, MIN(price_discount) md 
FROM    product_items 
GROUP   BY product_id

第二个视图

CREATE VIEW MinimumPriceList
AS 
SELECT  m.* 
FROM    product_items m 
        INNER JOIN MinimumPrice mm 
            ON  m.product_id = mm.product_id AND 
                m.price_discount = mm.md

要查询主视图,

SELECT * FROM MinimumPriceList

A view definition is subject to the following restrictions: FROM MySQL MANUAL

SELECT 语句的 FROM 子句中不能包含子查询。 SELECT 语句不能引用系统或用户变量。 在存储的程序中,定义不能引用程序参数或局部变量。 ....

【讨论】:

谢谢!我现在可以工作了。这有点迂回,但又一次;它工作。谢谢你!! 由于性能原因,嵌套视图不是很糟糕吗?

以上是关于MySQL的子查询中FROM和EXISTS子句的使用教程的主要内容,如果未能解决你的问题,请参考以下文章

EXISTS 不适用于 WITH 子句中的子查询

带有联合错误的 MySQL 视图 - “视图的 SELECT 包含 FROM 子句中的子查询”

带有“Exists”子句的子查询,其中需要从两个表中收集信息

EXISTS 和 IN 的区别

MySql VIEW 删除 FROM 条件下的子查询

SQL中的子查询