将 SQL 查询从 with 子句转移到没有 with 子句
Posted
技术标签:
【中文标题】将 SQL 查询从 with 子句转移到没有 with 子句【英文标题】:Transferring SQL query from with clause to without with clause 【发布时间】:2021-12-14 03:47:43 【问题描述】:考虑查询:
查找总工资大于所有部门总工资平均值的所有部门
with dept_total (dept_name, value) as
(
select dept_name, sum(salary)
from instructor
group by dept_name
),
dept_total_avg(value) as
(
select avg(value)
from dept_total
)
select dept_name
from dept_total, dept_total_avg
where dept_total.value >= dept_total avg.value;
在不使用 with 构造的情况下重写此查询。
查询基于由 Korth 的数据库系统概念提供的大学模式。我假设我只需要考虑讲师表即可找到查询的答案。
讲师(ID、姓名、部门名称、薪水)
我可以找到所有部门总工资的平均值
SELECT AVG(salary) GROUP BY dept_name;
然后我输了。我没有找到继续的方法。
我找到了that。但我正在寻找更多解释,因为我无法从这个链接中理解它。
感谢您的帮助。
【问题讨论】:
Bad habits to kick : using old-style JOINs - 旧式 逗号分隔的表格列表 样式已替换为 ANSI 中的 proper ANSIJOIN
语法-92 SQL 标准(差不多 30 年前),不鼓励使用它
【参考方案1】:
以下是在不支持 CTE 的 mysql 版本中执行此操作的几种方法(我假设这就是他们让您重写查询以省略 with 的原因)。此外,您正在按部门计算平均工资,但问题是要求找到每个部门的平均 TOTAL 工资,然后返回高于该平均工资的那些。
https://dbfiddle.uk/?rdbms=mysql_5.5&fiddle=fefea829cff3e20aea93634f9a4114d6
使用子查询:
SELECT dept_name
FROM (
SELECT dept_name, sum(salary) as salaries
FROM instructor GROUP BY dept_name
) d
WHERE salaries > (
SELECT avg(salaries) as avgSalaries FROM (
SELECT dept_name, sum(salary) as salaries
FROM instructor GROUP BY dept_name
) z
)
加入:
SELECT dept_name
FROM (
SELECT dept_name, sum(salary) as salaries
FROM instructor GROUP BY dept_name
) d
CROSS JOIN (
SELECT avg(salaries) as avgSalaries FROM (
SELECT dept_name, sum(salary) as salaries
FROM instructor GROUP BY dept_name
) z
) avgs
WHERE salaries > avgs.avgSalaries
使用会话变量(在以后的版本中已弃用,但仍然有效):
SELECT avg(salaries) INTO @avg FROM (
SELECT dept_name, sum(salary) as salaries
FROM instructor GROUP BY dept_name
) z;
SELECT @avg;
SELECT dept_name
FROM instructor GROUP BY dept_name
HAVING sum(salary) > @avg;
所有好的技术都可以理解。
【讨论】:
我会选择 INNER JOIN ... ON,而不是 CROSS JOIN ... WHERE。 我也是,可能。我认为它们在优化器中可能会出现相同的结果,但我想我想强调的是,由于您要加入一行结果集,所以加入条件并不重要,我正在使用结果只是作为比较器。可能应该只是这么说而不是那样写。我不确定我最后一次真正使用交叉连接是什么时候。 用子查询解决方案d和z代表什么? 在 mySQL 中,每个派生表都需要一个别名,因此 d 和 z 只是嵌套选择语句的别名。如果要从嵌套选择中进行选择,则必须为其命名。这些只是方便。我选择 d 作为第一个,因为它是 dept_name 的第一个字母,而另一个是 z,因为通常我从 z 开始,如果我不知道马上要嵌套多少层,我会在字母表中向后工作。 d 和 z 在这里可以是任何东西。你可以使用任何别名。【参考方案2】:看了你上一个问题,发现你用的是mysql5.8,那么就可以使用分析功能了
select distinct t1.dept_name
from (
select t1.*,
sum(salary) over(partition by dept_name) val,
sum(salary) over() / count(distinct dept_name) over() avg
from Instructor t1
) t1
where t1.val > t1.avg
【讨论】:
以上是关于将 SQL 查询从 with 子句转移到没有 with 子句的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server - 在 INSERT 语句中使用 WITH 子句