我试图编写一个聚合表中数据的查询。
基本上,我有很长的设备列表,这些设备已经过库存并最终安装在过去几年中。
我想查找收到设备和安装设备之间的平均时间,然后按设备安装月份排序。但是在每个月的行中,我还想包括前几个月的数据。
基本上我想看到的是:(抱歉可怕的格式化)
MonthInstalled | TimeToInstall | Total#Devices
-----------------+---------------+----------------------------
Jan | 10 Days | 5
Feb(=Jan+Feb) | 15 Days | 18 (5 in Jan + 13 in Feb)
Mar(=Jan+Feb+Mar)| 13 Days | 25 (5 + 13 + 7)
...
我目前编写的查询如下所示:
INSERT INTO DevicesInstall
SELECT ROUND(AVG(DATEDIFF(dvc.dt_install , dvc.dt_receive)), 1) AS 'Install',
COUNT(dvc.dvc_model) AS 'Total Devices',
MAX(dvc.dt_install) AS 'Date',
loc.loc_campus AS 'Campus'
FROM dvc_info dvc, location loc
WHERE dvc.dvc_loc_bin = loc.loc_bin
AND dvc.dt_install < '20160201'
;
虽然这是有用的,但我必须手动每月迭代一次,因此它无法扩展。有没有办法压缩这个?
答案 0 :(得分:0)
我们可以使用内联视图(派生表)返回日期,然后加入dvc_info
表,这样我们就可以获得&#34;累积&#34;结果
获取结果:
Jan
Jan+Feb
Jan+Feb+Mar
我们需要为Jan返回三个行副本,并为Feb返回两个行副本,然后将这些行折叠到适当的组中。
loc_campus
被包含在SELECT列表中......不清楚为什么需要它。如果我们想要结果&#34; by campus&#34;,那么我们需要在GROUP BY子句中包含该表达式。否则,为该非聚合返回的值是不确定的...我们将在组&#34;中获得某行&#34;的值,但它可以是任何行。
这样的事情:
SELECT d.dt AS `before_date`
, loc.loc_campus AS `Campus`
, ROUND(AVG(DATEDIFF(dvc.dt_install,dvc.dt_receive)),1) AS `Install`
, COUNT(dvc.dvc_model) AS `Total Devices`
, MAX(dvc.dt_install) AS `latest_dt_install`
FROM ( SELECT '2016-01-01' + INTERVAL 1 MONTH AS dt
UNION ALL SELECT '2016-01-01' + INTERVAL 2 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 3 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 4 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 5 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 6 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 7 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 8 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 9 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 10 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 11 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 12 MONTH
) d
CROSS
JOIN location loc
LEFT
JOIN dvc_info dvc
ON dvc.dvc_loc_bin = loc.loc_bin
AND dvc.dt_install < d.dt
GROUP
BY d.dt
, loc.loc_campus
ORDER
BY d.dt
, loc.loc_campus
请注意,d.dt
返回的值将是&#34;直到&#34;日期。我们要去2016-02-01&#39;返回1月份的结果。如果我们想要返回1月日期的值,我们可以使用SELECT列表中的表达式...
SELECT DATE_FORMAT(d.dt + INTERVAL -1 MONTH,'%Y-%m') AS `month`
有关查询替代方案的大量选项。
但它看起来像是&#34;大驼峰&#34;是为了获得累积结果,我们需要返回dvc_info
行的多个副本,因此可以将行折叠到每个&#34;分组&#34;。
我建议先处理SELECT
。并且在进行调整之前将其转换为INSERT ... SELECT
。
关注
我们可以将任何查询用作内联视图(派生表d
),它返回我们想要的一组日期。
e.g。
FROM ( SELECT DATE_FORMAT(m.install_dt,'%Y-%m-01') + INTERVAL 1 MONTH AS dt
FROM dvc_install m
WHERE m.install_dt >= '2016-01-01'
GROUP BY DATE_FORMAT(m.install_dt,'%Y-%m-01') + INTERVAL 1 MONTH
) d
请注意,使用这种方法,如果2月份没有install_dt
,我们将无法获得2月份的回复。使用静态UNION ALL SELECT
方法可以让我们回归&#34;零&#34;计数,即在那个月没有install_dt的月份返回行数。 (但那是另一个问题的答案......如果没有任何行可用于二月,我如何得到2月份的&#34;零&#34;计数?)
或者,如果我们有一个日历表,例如cal
包含我们想要的日期列表,我们可以引用该表代替内联视图,或者内联视图查询可以从中获取行。
FROM ( SELECT cal.dt
FROM cal cal
WHERE cal.dt >= '2016-01-01'
AND cal.dt <= NOW()
AND DATE_FORMAT(cal.dt,'%d') = '01'
) d