当SELECT后面的子查询不能被删除?

Posted

技术标签:

【中文标题】当SELECT后面的子查询不能被删除?【英文标题】:When subquery behind SELECT can not be removed? 【发布时间】:2017-11-02 21:16:36 【问题描述】:

相关子查询被视为bad habit。我相信任何带有SELECTFROM 之间子查询的SQL 命令(我们称之为SELECT 子查询)都可以重写为没有任何子查询的SQL。例如这样的查询

select *,
(
  select sum(t2.sales)
  from your_table t2
  where t2.dates
         between t1.dates - interval '3' day and 
                 t1.dates and 
       t2.id = t1.id
) running_sales
from your_table t1

demo

可以改写成下面一个

 select dd.id, dd.dates, dd.sales, sum(d.sales) running_sales
 from your_table dd
 join your_table d on d.dates
     between (dd.dates - interval '3' day) and 
              dd.dates and 
     dd.id = d.id
 group by dd.id, dd.dates, dd.sales

demo

当有多个SELECT子查询时可能会出现问题,但是即使在这种情况下,也可以将它们重写为FROM后面的子查询,然后按照以下精神执行LEFT JOIN

select *,
(
  select sum(sales)
  from dat dd
  where dd.dates
         between (d.dates - interval '3' day) and d.dates and 
         dd.id = d.id
) running_sales,
(
  select sum(sales)
  from dat dd
  where dd.id = d.id
) total_sales
from dat d

demo

可以改写成下面一个

select d.*,
   t_running.running_sales,
   t_total.total_sales
from dat d
left join (
  select dd.id, dd.dates, sum(d.sales) running_sales
  from dat dd
  join dat d on d.dates
          between (dd.dates - interval '3' day) and 
                   dd.dates and 
          dd.id = d.id
  group by dd.id, dd.dates
) t_running on d.id = t_running.id and d.dates = t_running.dates
left join (
  select d.id, sum(d.sales) total_sales
  from dat d
  group by d.id    
) t_total on t_total.id = d.id

demo

您能否提供一个示例,说明 不可能 摆脱 SELECT 子查询?请善待并添加一个工作示例链接(例如dbfiddle 或sqlfiddle)以使潜在的讨论更容易,谢谢!

【问题讨论】:

我真的不知道这是否是 SE 的主题?...无论如何,我会给出“不”的答案,select 语句中的子查询总是可以用更好的方式。 我同意,这是题外话。也就是说,有时为了清楚起见,使用子查询是合适的。我的主数据库是 Oracle,而不是你标签中的 SQL*Server,但是我已经在 Oracle 上编写了两种查询方式并且收到了相同的解释计划,所以它在性能方面没有任何区别。 @BrianLeach 好的,为什么它被认为是一个坏习惯呢?我在比提供的链接更多的地方阅读了这样的意见。 它们总是可以轻松地交换到外部应用中。前 N 个子查询不能被重写为一个连接,尽管没有彻底重写以使用不同的结构,例如行号。 我同意这通常是个坏主意。我看到它以有效方式使用的唯一地方是从 CRM 数据库中检索数据的情况,该数据库在过滤视图上使用行级安全性。在选择子查询中检索查找数据减少了需要检查安全性的记录数量并显着提高了性能。然而,每当我看到其中一个查询时,我仍然会畏缩。 【参考方案1】:

如果问题是针对多项选择测试(或类似的测试):),则无法摆脱 EXISTS 子句的子查询。

另一个类似的答案是 IN (subquery) 用于不同级别的聚合以避免笛卡尔积。

(顺便说一句:相关的子查询并不是每次都认为是一个坏习惯,它取决于优化、结构等......

WITH 是一种相关子查询的使用...对于复杂的查询非常实用。 )

【讨论】:

以上是关于当SELECT后面的子查询不能被删除?的主要内容,如果未能解决你的问题,请参考以下文章

SQL里的子查询

MySQL 子查询使用方式

MySQL 子查询使用方式

08-子查询

MYSQLupdate/delete/select语句中的子查询

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