假设我有下一张表,第一个表只存储设备及其序列号和其他数据(与问题无关),因此可以简化为:
CREATE TABLE `tbl_devices` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`SERIAL` varchar(100) DEFAULT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `unique_serial` (`SERIAL`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
这些设备以一定频率发送带宽消耗日志,并将它们存储在下表中:
CREATE TABLE `tbl_log_bandwidth` (
`ID` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`DEV_ID` int(11) NOT NULL,
`DIR_ID` smallint(6) UNSIGNED NOT NULL,
`PROTOCOL_ID` smallint(6) UNSIGNED NOT NULL,
`KILOBYTES` int(11) UNSIGNED NOT NULL,
`EVAL_TIME` int(11) UNSIGNED NOT NULL,
`DATE` datetime NOT NULL,
PRIMARY KEY (`ID`),
KEY `idx_devices` (`DEV_ID`),
KEY `idx_direction_id` (`DIR_ID`),
KEY `idx_protocol_id` (`PROTOCOL_ID`),
KEY `idx_devices_date` (`DEV_ID`,`DATE`),
CONSTRAINT `fk_tbl_devices`
FOREIGN KEY (`DEV_ID`) REFERENCES `tbl_devices` (`ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_tbl_dir_type`
FOREIGN KEY (`DIR_ID`) REFERENCES `tbl_dir_type` (`ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_tbl_protocol_type`
FOREIGN KEY (`PROTOCOL_ID`) REFERENCES `tbl_protocol_type` (`ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
其他表( tbl_dir_type和tbl_protocol_type )仅存储静态信息:
CREATE TABLE `tbl_dir_type` (
`ID` smallint(6) UNSIGNED NOT NULL,
`NAME` varchar(50) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `tbl_dir_type` VALUES
(1,'Download'),
(2,'Upload');
CREATE TABLE `tbl_protocol_type` (
`ID` smallint(6) UNSIGNED NOT NULL,
`NAME` varchar(50) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `tbl_protocol_type` VALUES
(1,'HTTP'),
(2,'HTTPS'),
(3,'POP3'),
(4,'SMTP'),
(5,'FTP'),
(6,'ADB'),
(99,'OTHER');
目标:
我需要实现的目标是,获得在特定小时范围内评估的最近N天中按天和方向ID分开的总带宽消耗的报告。到目前为止,我已经进行了下一个查询(假设N = 5,并且小时范围是09:00至18:00):
SELECT
dev.SERIAL,
DATE(log.DATE),
SUM(CASE WHEN log.DIR_ID = 1 THEN log.KILOBYTES ELSE 0 END) / 1024 AS DOWNLOAD_MB,
SUM(CASE WHEN log.DIR_ID = 2 THEN log.KILOBYTES ELSE 0 END) / 1024 AS UPLOAD_MB
FROM
tbl_devices AS dev
INNER JOIN
tbl_log_bandwidth AS log ON log.DEV_ID = dev.ID
WHERE
log.DATE >= DATE_ADD(DATE(now()), INTERVAL -4 DAY)
AND
HOUR(log.DATE) BETWEEN 09 AND 18
GROUP BY
log.DEV_ID, log.DATE
上一个查询给我每个设备5行(每天1行),如下一个示例:
SERIAL DATE DOWNLOAD_MB UPLOAD_MB
9000321982F3C585084 2018-10-02 34.5898 3.0186
9000321982F3C585084 2018-10-01 35.5703 3.2041
9000321982F3C585084 2018-09-30 34.9980 3.1123
9000321982F3C585084 2018-09-29 34.8496 3.0977
9000321982F3C585084 2018-09-28 91.0010 6.2588
但是,我想走得更远,对于具有下一个结构的每台设备,只能获得一行:
SERIAL DOWN_2018-10-02 UP_2018-10-02 DOWN_2018-10-01 UP_2018-10-01 DOWN_2018-09-30 UP_2018-09-30 ...
9000321982F3C585084 34.5898 3.0186 35.5703 3.2041 34.9980 3.1123 ...
使用PIVOT功能进行查询更新
在阅读了一些枢轴示例之后,我进入了下一个查询:
SELECT
dev.SERIAL,
SUM(CASE WHEN log.DIR_ID = 1 AND DATE(log.DATE) = DATE(NOW())
THEN log.KILOBYTES ELSE 0 END) / 1024 AS DOWN_TODAY,
SUM(CASE WHEN log.DIR_ID = 2 AND DATE(log.DATE) = DATE(NOW())
THEN log.KILOBYTES ELSE 0 END) / 1024 AS UP_TODAY,
SUM(CASE WHEN log.DIR_ID = 1 AND DATE(log.DATE) = DATE_ADD(DATE(NOW()), INTERVAL -1 DAY)
THEN log.KILOBYTES ELSE 0 END) / 1024 AS DOWN_TODAY_MINUS_1DAY,
SUM(CASE WHEN log.DIR_ID = 2 AND DATE(log.DATE) = DATE_ADD(DATE(NOW()), INTERVAL -1 DAY)
THEN log.KILOBYTES ELSE 0 END) / 1024 AS UP_TODAY_MINUS_1DAY,
SUM(CASE WHEN log.DIR_ID = 1 AND DATE(log.DATE) = DATE_ADD(DATE(NOW()), INTERVAL -2 DAY)
THEN log.KILOBYTES ELSE 0 END) / 1024 AS DOWN_TODAY_MINUS_2DAYS,
SUM(CASE WHEN log.DIR_ID = 2 AND DATE(log.DATE) = DATE_ADD(DATE(NOW()), INTERVAL -2 DAY)
THEN log.KILOBYTES ELSE 0 END) / 1024 AS UP_TODAY_MINUS_2DAYS,
SUM(CASE WHEN log.DIR_ID = 1 AND DATE(log.DATE) = DATE_ADD(DATE(NOW()), INTERVAL -3 DAY)
THEN log.KILOBYTES ELSE 0 END) / 1024 AS DOWN_TODAY_MINUS_3DAYS,
SUM(CASE WHEN log.DIR_ID = 2 AND DATE(log.DATE) = DATE_ADD(DATE(NOW()), INTERVAL -3 DAY)
THEN log.KILOBYTES ELSE 0 END) / 1024 AS UP_TODAY_MINUS_3DAYS,
SUM(CASE WHEN log.DIR_ID = 1 AND DATE(log.DATE) = DATE_ADD(DATE(NOW()), INTERVAL -4 DAY)
THEN log.KILOBYTES ELSE 0 END) / 1024 AS DOWN_TODAY_MINUS_4DAYS,
SUM(CASE WHEN log.DIR_ID = 2 AND DATE(log.DATE) = DATE_ADD(DATE(NOW()), INTERVAL -4 DAY)
THEN log.KILOBYTES ELSE 0 END) / 1024 AS UP_TODAY_MINUS_4DAYS
FROM
tbl_devices AS dev
INNER JOIN
tbl_log_bandwidth AS log ON log.DEV_ID = dev.ID
WHERE
log.DATE >= DATE_ADD(DATE(now()), INTERVAL -4 DAY)
AND
HOUR(log.DATE) BETWEEN 09 AND 18
GROUP BY
log.DEV_ID, dev.SERIAL
但是现在,我还有下一个问题:
1)如何处理列的动态性,这取决于评估中使用的最近N天的数量。
2),有什么方法可以评估表达式并将其用作列名?如您所见,我的列具有“ DOWN_TODAY ”,“ DOWN_TODAY_MINUS_1DAY ”等名称。但是,我希望它们像下一个表达式的结果一样被命名: / p>
CONCAT("DOWN_", DATE(NOW()))
CONCAT("DOWN_", DATE_ADD(DATE(NOW()), INTERVAL -1 DAY))
...