子查询是否为SQL查询增加了表达能力?


29

SQL是否需要子查询?

想象一下关系数据库的结构化查询语言的足够通用的实现。由于规范SQL SELECT语句的结构实际上对于使其有意义很重要,因此我不直接诉诸关系代数,但是您可以通过对表达式的形式进行适当的限制来用这些术语来构架。

一个SQL SELECT查询通常由投影(的SELECT部分)的一些数目的JOIN操作(JOIN部分),一些数目的SELECTION 操作(在SQL中,WHERE条款),然后设置为单位的运算(UNIONEXCEPTINTERSECT等),接着再SQL SELECT查询。

被连接的表可以是表达式的计算结果。换句话说,我们可以有一条语句,例如:

SELECT t1.name, t2.address
  FROM table1 AS t1 
  JOIN (SELECT id, address 
          FROM table2 AS t3 
         WHERE t3.id = t1.id) AS t2
 WHERE t1.salary > 50,000;

我们将使用计算表作为SQL查询的一部分称为子查询。在上面的示例中,第二个(缩进的)SELECT是一个子查询。

能否以不使用子查询的方式编写所有SQL查询?上面的示例可以:

SELECT t1.name, t2.address
  FROM table1 AS t1 
  JOIN table2 AS t2
    ON t1.id = t2.id
 WHERE t1.salary > 50,000;

这个例子有些虚假,或者是琐碎的,但是可以想象实例中需要花费更多的精力来恢复等效的表达式。换句话说,是否对于每个带有子查询的SQL查询,都存在一个没有子查询的查询q ',从而确保qq '对于相同的基础表产生相同的结果?让我们将SQL查询限制为以下形式:qqqq

SELECT <attribute>,
      ...,
      <attribute>
 FROM <a table, not a subquery>
 JOIN <a table, not a subquery>
  ...
 JOIN <a table, not a subquery>
WHERE <condition>
  AND <condition>
  ...
  AND <condition>

UNION
 -or-
EXCEPT
 -or-
<similar>

SELECT ...

等等。我认为左右外连接并没有增加多少,但是如果我弄错了,请随时指出……无论如何,它们也是公平的游戏。就集合运算而言,我猜它们中的任何一个都很好……并集,差,对称差,交集等……任何有用的东西。是否存在可以将所有SQL查询简化为的已知形式?这些方法是否消除了子查询?还是在某些情况下不存在等效的无子查询的查询?引用是值得赞赏的...或者证明(不需要证明)证明将是很棒的。谢谢,如果这是庆祝(或微不足道)的结果,对此我感到无知,请对不起。


5
我的直觉告诉我,只要不需要聚合值,就可以始终将所有内容结合在一起并从中进行选择。选择值大于其列平均值的所有条目似乎需要首先计算平均值,因此需要一个子查询。
拉斐尔

@Raphael我敢肯定,您甚至可以做聚合的值,您只需要执行更多的自联接和分组操作即可(使其成倍地增大,但仍然可以实现)。不过,我不确定我将如何正式证明您可以做到这一点。
凯文2012年

@Kevin您确定所需的操作数不取决于行数吗?因为我们不能拥有,可以吗?
拉斐尔

1
我要求子查询的普通示例正在计算重复项:select count(*) from (select id from sometable group by id having count(*)>1) d。因为它包括group by我没有回答这个问题。
马克·赫德

BTW AFAIK在常规SQL中ONJOINs 是必需的子句,尽管仅使用逗号即可获得叉积。
马克·赫德2012年

Answers:


9

有一些术语混淆;括号内的查询块

SELECT t1.name, t2.address
  FROM table1 
  JOIN (SELECT id, address 
          FROM table2 AS t3 
         WHERE t3.id = t1.id) 

被称为内部视图。甲子查询是内要么WHERE或SELECT子句,例如查询块

select deptno from dept
where 3 < (select count(1) from emp 
           where dept.deptno=emp.deptno)

无论哪种情况,都可以将内部视图或子查询取消嵌套到“平面” project-restrict-join中。具有聚合的相关子查询将取消嵌套到具有分组的内部视图中,然后将其嵌套到平面查询中。

select deptno from dept d
    where 3 < (select avg(sal) from emp e
               where d.deptno=e.deptno)

select d.deptno from dept d, ( 
    select deptno from emp e
    group by deptno
    having avg(sal) > 3
) where d.deptno=e.deptno

select d.deptno from dept d, emp e
where d.deptno=e.deptno 
group by d.deptno
having avg(sal) > 3

至于查询优化的代数规则,已知将关系代数公理化为 关系格,这简化了查询转换,如此此处所示


我好奇。您是否可以添加一个查询示例,该查询使用某些字段的平均值,例如选择所有高于平均值的条目?我不清楚展平后的样子。
拉斐尔

16

为了将您的陈述转换为关系代数,我认为它要求:

σ一种一种σσ一种σ一种

σ

答案是“是”,这是标准的查询优化。老实说,我不确定如何以无问题的方式证明这一点-这只是选择和加入的属性。您可以归纳性地争论添加所需的嵌套查询的任何多层。

此外,您可能会问:

一种C一种Cd ]

同样,答案是肯定的,因为联接是关联的。关于投影也可以做出类似的陈述。

我认为无法“扁平化”的一种值得注意的“子查询”类型是with。看到这种情况的一种方法是注意,如果您有with语句,那么您可以拥有一个递归函数,如果不使用子查询就无法编写该函数。

综上所述:在您提​​到的特定情况下,不,SQL不需要子查询,您可以归纳证明它。通常,有些功能需要子查询。


递归行为通过 withSQL:1999中引入了,并且使所得的语言严格更具表达性。
安德拉斯·萨拉蒙

1

“子查询是否为SQL查询增加了表达能力?”

他们做到了,至少在以SQL语言引入EXCEPT之前。

在引入EXCEPT之前,没有任何方法可以在不诉诸子查询的情况下表达SQL中的关系差异或半差异。

如今,关系代数的所有“典型”原始运算符都可以不用子查询来表示:

可以通过NATURAL JOIN或JOIN ON来完成NATURAL JOIN
通过UNION
MINUS 进行 UNION可以通过EXCEPT
PROJECT / RENAME / EXTEND进行。可以通过SELECT
RESTRICT进行通过WHERE
关系文字可以通过VALUES
传递闭包可以完成。通过递归使用

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.