如何在嵌套的二级子查询中使用外部表?

时间:2019-03-23 06:28:37

标签: mysql sql

我的查询如下:

SELECT codes.id, (SELECT SUM(PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM a.end_date), EXTRACT(YEAR_MONTH FROM a.start_date))) months
  FROM (
    SELECT MIN(g.start_date) start_date, MAX(g.end_date) end_date 
      FROM (
        SELECT @group_id := @group_id + (@end_date IS NULL OR o.start_date > @end_date) group_id,
               start_date,
               @end_date := DATE(CASE 
                 WHEN (@end_date IS NULL OR o.start_date > @end_date) THEN o.end_date
                 ELSE GREATEST(o.end_date, @end_date)
               END) end_date  
          FROM dates_range o
          JOIN (SELECT @group_id := 0, @end_date := NULL) init
          WHERE o.code_id = codes.id -- THIS CLAUSE DOES NOT WORK 
      ORDER BY o.start_date ASC  
            ) g
  GROUP BY  g.group_id  
        ) a) as sum_date_ranges
FROM codes
-- A LOT OF JOINs and WHEREs OF codes.id THAT I CAN NOT MOVE INSIDE THE NESTED TWO LEVEL SUBQUERY

正如注释中所写,WHERE子句不起作用,但是我需要在嵌套的二级子查询中使用codes.id。我该怎么办?

MySQL错误:

Unknown column 'codes.id' in 'where clause'

1 个答案:

答案 0 :(得分:0)

无法从派生表访问外部表(简化一下,在您的情况下,这是任何需要别名的“子查询”,g和{{ 1}})。

您必须使用a在外部进行必要的操作。为此,您需要跟踪join并将其传递到外部级别:

o.code_id

对于每个新的SELECT codes.id, sum_date_ranges.sum_date_ranges FROM codes JOIN (SELECT a.code_id, SUM( ... ) as sum_date_ranges (SELECT g.code_id, g.group_id, MIN( ... ), MAX( ... ) FROM ( SELECT o.code_id, @group_id = ... FROM dates_range o ... -- WHERE o.code_id = codes.id -- not required ORDER BY o.code_id, o.start_date ) g GROUP BY g.code_id, g.group_id ) a GROUP BY a.code_id ) as sum_date_ranges ON sum_date_ranges.code_id = codes.id -- the rest of your joins and where-conditions ,您可能需要熟练使用@group_id = ...才能从0重新开始,但是由于您似乎并没有在任何地方使用绝对值,因此可能没有关系。

这将为每个o.code_id评估完整的派生表,然后丢弃它不需要的所有内容(可能会或可能不会成为数据的重要部分)。为了防止这种情况,您可以改为将外部条件放入查询中:

code_id

这假设您实际上只需要SELECT sum_date_ranges.code_id as id, sum_date_ranges.sum_date_ranges -- from codes -- not required anymore, we get codes.id from derived table FROM (SELECT a.code_id, SUM( ... ) as sum_date_ranges (SELECT g.code_id, g.group_id, MIN( ... ), MAX( ... ) FROM ( SELECT o.code_id, @group_id = ... FROM dates_range o ... WHERE o.code_id IN (SELECT codes.id FROM codes -- your join and where-conditions ) ORDER BY o.code_id, o.start_date ) g GROUP BY g.code_id, g.group_id ) a GROUP BY a.code_id ) as sum_date_ranges -- optionally in case you need other columns from codes -- JOIN codes ON codes.id = sum_date_ranges.code_id 中的列codes.id(并且您的codes不会乘以行),但是在这方面您的查询可能已经简化了,所以当然,您仍然可以再次联接joins(和其他表)以获取所需的列(但这里不再需要codes条件)。

可能可以完全重写查询而无需派生表,但是可能需要进行大量修改并且不太可能使用变量。如果从头开始,这可能是最简单的方法(如果需要帮助,则需要提供完整的查询,示例数据,预期输出以及代码应执行的一些解释)。具体来说,如果您使用MySQL 8,则可能会使用window functions而不是变量来获得这种排名,总和,第一个和最后一个值,尽管看起来您毕竟仍然需要一个派生表。