MySQL重用子查询

时间:2015-12-05 10:21:09

标签: mysql sql stored-procedures subquery

我在这里阅读了一些关于子查询重用的线程,但找不到令人满意的问题答案:假设下表 temp (在MySQL中):

+------+---+----+
| Y    | M | V  |
+------+---+----+
| 1995 | 0 |  3 |
| 1995 | 1 | 16 |
| 1995 | 4 | 18 |
| 2025 | 0 |  4 |
| 2025 | 2 | 13 |
+------+---+----+

我想生成一个新的列X,它将V从M为0的行复制到具有相同Y(ear)的所有行,例如:

+------+---+----+------+
| Y    | M | V  | X    |
+------+---+----+------+
| 1995 | 0 |  3 |    3 |
| 1995 | 1 | 16 |    3 |
| 1995 | 4 | 18 |    3 |
| 2025 | 0 |  4 |    4 |
| 2025 | 2 | 13 |    4 |
+------+---+----+------+

这可以这样做:

SELECT Y, M, V,
  (SELECT V FROM temp WHERE temp.Y = t.Y AND M = 0) AS X
FROM temp t;

或者像这样:

SELECT temp.Y, temp.M, temp.V, q2.V AS X
FROM temp
JOIN (SELECT * FROM temp WHERE M = 0) q2 USING (Y);

出于本练习的目的,可以假设 temp 每个Y(耳朵)只包含一个M = 0.

麻烦的是, temp 实际上不是一个表,而是一个复杂查询的结果。用实际查询替换temp是不实用的,并且性能可能会很差,除非MySQL足够聪明地检测到这两个结构是相同的。

在MySQL中没有WITH子句,有没有办法生成X而不需要两次引用 temp ;即是这个问题真正需要的子查询吗?

代码最终将在S-PROC中运行,因此我可以创建一个临时内存表,但我想知道是否有更多优雅的解决方案。

1 个答案:

答案 0 :(得分:2)

公用表表达式和子查询是最简单的方法。视图是一种解决方案。另一种是使用变量:

select t.*,
       (@v := if(@y = y, @v,
                 if(@y := y, v, v)
                )
       )
from temp t cross join
     (select @y := 0, @v := -1) params
order by year, (m = 0) desc;

请注意,此公式强烈假设每年至少有一个值m = 0 - 它会复制该年度所有行的每年遇到的第一个值。您在问题描述中指定这是真的。表达可以更复杂一些,以涵盖一年没有这样一行的情况(但这将是一个不同的问题)。