我有一个存储简单日志数据的表:
CREATE TABLE chronicle (
id INT auto_increment PRIMARY KEY,
data1 VARCHAR(256),
data2 VARCHAR(256),
time DATETIME
);
该表接近1m记录,因此我想开始整合数据。
我希望每天能够记录每个DISTINCT(data1, data2)
的第一个和最后一个记录,并删除所有其余记录。
我知道如何只使用我想要的任何语言提取数据并处理它,然后使用巨大的IN (...)
query删除记录,但似乎更好的选择是直接使用SQL(我错了吗? )
我已经尝试了几个查询,但是我对JOIN之外的SQL不太满意。
这是我到目前为止所做的:
SELECT id, Max(time), Min(time)
FROM (SELECT id, data1 ,data2, time, Cast(time AS DATE) AS day
FROM chronicle) AS initial
GROUP BY day;
这让我每天都是第一次也是最后一次,但它没有被数据分开(即我得到每天的最后一条记录,而不是每天每组不同数据的最后一条记录。)另外,id
仅适用于Min(时间)。
我在这个特定问题上找到的信息仅用于查找当天的最后一条记录,而不是每组数据的最后记录。
重要提示:我想要每天DISTINCT(data1, data2)
的第一个/最后一个记录,而不仅仅是表格中每天的第一个/最后一个记录。每天将有超过2条记录。
解决方案: 我的解决方案归功于Jonathan Dahan和Gordon Linoff:
SELECT o.data1, o.data2, o.time FROM chronicle AS o JOIN (
SELECT Min(id) as id FROM chronicle GROUP BY DATE(time), data1, data2
UNION SELECT Max(id) as id FROM test_chronicle GROUP BY DATE(time), data1. data2
) AS n ON o.id = n.id;
从这里开始,引用同一个表来删除行就很简单了。
答案 0 :(得分:1)
你有正确的想法。您只需加入即可获取原始信息。
SELECT c.*
FROM chronicle c JOIN
(SELECT date(time) as day, min(time) as mint, max(time) as maxt
FROM chronicle
GROUP BY date(time)
) cc
ON c.time IN (cc.mint, cc.maxt);
请注意,join
条件不需要明确包含day
,因为它是time
的一部分。当然,如果您愿意,可以添加date(c.time) = cc.day
。
我建议您创建一个新表,而不是删除原始表中的行。有点谎言:
create table ChronicleByDay like chronicle;
insert into ChronicleByDay
SELECT c.*
FROM chronicle c JOIN
(SELECT date(time) as day, min(time) as mint, max(time) as maxt
FROM chronicle
GROUP BY date(time)
) cc
ON c.time IN (cc.mint, cc.maxt);
这样,如果您需要,可以获得更详细的信息。
答案 1 :(得分:1)
这会在日期搜索时提高效果。
ALTER TABLE chronicle
ADD INDEX `ix_chronicle_time` (`time` ASC);
这将删除记录:
CREATE TEMPORARY TABLE #tmp_ids (
`id` INT NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO #tmp_ids (id)
SELECT
min(id)
FROM
chronicle
GROUP BY
CAST(day as DATE),
data1,
data2
UNION
SELECT
Max(id)
FROM
chronicle
GROUP BY
CAST(day as DATE),
data1,
data2;
DELETE FROM
chronicle
WHERE
ID not in (select id FROM #tmp_ids)
AND date <= '2015-01-01'; -- if you want to consider all dates, then remove this condition