我有一张看起来像这样的表:
DataTable
+------------+------------+------------+
| Date | DailyData1 | DailyData2 |
+------------+------------+------------+
| 2012-01-23 | 146.30 | 212.45 |
| 2012-01-20 | 554.62 | 539.11 |
| 2012-01-19 | 710.69 | 536.35 |
+------------+------------+------------+
我正在尝试创建一个视图(称之为AggregateView
),对于每个日期和每个数据列,它将显示一些不同的聚合。例如,select * from AggregateView where Date = '2012-01-23'
可能会给出:
+------------+--------------+----------------+--------------+----------------+
| Date | Data1_MTDAvg | Data1_20DayAvg | Data2_MTDAvg | Data2_20DayAvg |
+------------+--------------+----------------+--------------+----------------+
| 2012-01-23 | 697.71 | 566.34 | 601.37 | 192.13 |
+------------+--------------+----------------+--------------+----------------+
其中Data1_MTDAvg
显示1月23日之前1月份的每个日期avg(DailyData1)
,而Data1_20DayAvg
显示相同但表格中的前20个日期。我不是SQL忍者,但我认为最好的方法是通过子查询。 MTD平均值很简单:
select t1.Date, (select avg(t2.DailyData1)
from DataTable t2
where t2.Date <= t1.Date
and month(t2.Date) = month(t1.Date)
and year(t2.Date) = year(t1.Date)) Data1_MTDAvg
from DataTable t1;
但由于需要限制返回的结果数量,我在20天的平均值上挂了。请注意,表中的日期是不规则的,因此我不能使用日期间隔;我需要表格中的最后20条记录,而不是过去20天内的所有记录。我发现的唯一解决方案是使用嵌套子查询首先限制所选记录,然后取平均值。
单独,子查询适用于个别硬编码日期:
select avg(t2.DailyData1) Data1_20DayAvg
from (select DailyData1
from DataTable
where Date <= '2012-01-23'
order by Date desc
limit 0,20) t2;
但是试图将其作为更大查询的一部分嵌入其中:
select t1.Date, (select avg(t2.DailyData1) Data1_20DayAvg
from (select DailyData1
from DataTable
where Date <= t1.Date
order by Date desc
limit 0,20) t2)
from DataTable t1;
ERROR 1054 (42S22): Unknown column 't1.Date' in 'where clause'
从搜索中我得到的印象是你不能使用相关子查询作为from
子句的一部分,我认为这是问题所在。另一个问题是我不确定MySQL是否会接受子查询中包含from
子句的视图定义。有没有办法限制我的聚合选择中的数据而不诉诸子查询,以解决这两个问题?
答案 0 :(得分:1)
不,您不能在FROM
子句中使用相关的子查询。但您可以在ON
条件中使用它们:
SELECT AVG(d.DailyData1) Data1_20DayAvg
--- other aggregate stuff on d (Datatable)
FROM
( SELECT '2012-01-23' AS DateChecked
) AS dd
JOIN
DataTable AS d
ON
d.Date <= dd.DateChecked
AND
d.Date >= COALESCE(
( SELECT DailyData1
FROM DataTable AS last20
WHERE Date <= dd.DateChecked
AND (other conditions for last20)
ORDER BY Date DESC
LIMIT 1 OFFSET 19
), '1001-01-01' )
WHERE (other conditions for d Datatable)
类似,对于许多日期:
SELECT dd.DateChecked
, AVG(d.DailyData1) Data1_20DayAvg
--- other aggregate stuff on d (Datatable)
FROM
( SELECT DISTINCT Date AS DateChecked
FROM DataTable
) AS dd
JOIN
DataTable AS d
ON
d.Date <= dd.DateChecked
AND
d.Date >= COALESCE(
( SELECT DailyData1
FROM DataTable AS last20
WHERE Date <= dd.DateChecked
AND (other conditions for last20)
ORDER BY Date DESC
LIMIT 1 OFFSET 19
), '1001-01-01' )
WHERE (other conditions for d Datatable)
GROUP BY
dd.DateChecked
两个查询都假定Datatable.Date
有一个UNIQUE
约束。