Bạn có thể tạo các giá trị tứ phân vị bởi sử dụng IF để đặt chúng thành 0 nếu nằm trong phần tư sai:
Giả sử, bảng dữ liệu thô được tạo bởi
DROP TABLE IF EXISTS `rawdata`;
CREATE TABLE `rawdata` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(250) NOT NULL DEFAULT '',
`time` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `time` (`time`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
(và ofcourse dân cư).
hãy thử nghĩ xem các dữ liệu bảng tứ phân vị được tạo ra bởi
DROP TABLE IF EXISTS `quartiles`;
CREATE TABLE `quartiles` (
`url` varchar(250) NOT NULL,
`Q1` float DEFAULT '0',
`Q2` float DEFAULT '0',
`Q3` float DEFAULT '0',
`Q4` float DEFAULT '0',
PRIMARY KEY (`url`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
(và bỏ trống).
Sau đó, một thủ tục để cư tứ phân vị từ rawdata sẽ trông như thế
DELIMITER ;;
CREATE PROCEDURE `ComputeQuartiles`()
READS SQL DATA
BEGIN
DECLARE numrows int DEFAULT 0;
DECLARE qrows int DEFAULT 0;
DECLARE rownum int DEFAULT 0;
DECLARE done int DEFAULT 0;
DECLARE currenturl VARCHAR(250) CHARACTER SET utf8;
DECLARE Q1,Q2,Q3,Q4 float DEFAULT 0.0;
DECLARE allurls CURSOR FOR SELECT DISTINCT url FROM rawdata;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET currenturl='';
OPEN allurls;
FETCH allurls INTO currenturl;
WHILE currenturl<>'' DO
SELECT COUNT(*) INTO numrows FROM rawdata WHERE url=currenturl;
SET qrows=FLOOR(numrows/4);
if qrows>0 THEN
-- Only session parameters can be recalculated inside a query,
-- so @rownum:[email protected]+1 will work, but rownum:=rownum+1 will not.
SET @rownum=0;
SELECT
SUM(IFNULL(QA,0))/qrows,
SUM(IFNULL(QB,0))/qrows,
SUM(IFNULL(QC,0))/qrows,
SUM(IFNULL(QD,0))/qrows
FROM (
SELECT
if(@rownum<qrows,time,0) AS QA,
if(@rownum>=qrows AND @rownum<2*qrows,time,0) AS QB,
-- the middle 0-3 rows are left out
if(@rownum>=(numrows-2*qrows) AND @rownum<(numrows-qrows),time,0) AS QC,
if(@rownum>=(numrows-qrows),time,0) AS QD,
@rownum:[email protected]+1 AS dummy
FROM rawdata
WHERE url=currenturl ORDER BY time
) AS baseview
INTO Q1,Q2,Q3,Q4
;
REPLACE INTO quartiles values (currenturl,Q1,Q2,Q3,Q4);
END IF;
FETCH allurls INTO currenturl;
END WHILE;
CLOSE allurls;
END ;;
DELIMITER ;
Những điểm chính là:
- Sử dụng một con trỏ đến chu kỳ các URL (hoặc điều chỉnh mẫu để chấp nhận các URL như tham số)
- Đối với mỗi URL, hãy tìm tổng số hàng
- Thực hiện một số phép toán tầm thường để loại bỏ các hàng ở giữa, nếu
(rowcount % 4) != 0
- chọn tất cả các hàng thô cho URL, gán giá trị
time
cho một trong số QA-QD, tùy thuộc vào số hàng, gán giá trị Qx khác 0
- Sử dụng truy vấn này dưới dạng truy vấn phụ tổng kết và bình thường hóa các giá trị
- Sử dụng các kết quả của superquery này để cập nhật bảng tứ phân vị
tôi thử nghiệm này với 18.432 hàng thô, url=concat('http://.../',floor(rand()*10)), time=round(rand()*10000)
trên một máy 8x1.9GHz và nó đã hoàn thành một cách nhất quán trong 0.50-0.54sec
'SQL For Smarties' của Joe Celko có một chương thống kê (chế độ, trung bình, phương sai, v.v.) Nó đáng giá. –