2015-01-12 8 views
0

У меня есть таблица, которая хранит простые данные журнала:SQL - Держите только первую и последнюю запись каждого день

CREATE TABLE chronicle (
    id INT auto_increment PRIMARY KEY, 
    data1 VARCHAR(256), 
    data2 VARCHAR(256), 
    time DATETIME 
); 

Таблицы приближающихся записи 1х, поэтому я хотел бы начать объединение данных.

Я хочу, чтобы каждый день принимал первую и последнюю запись каждого DISTINCT(data1, data2) и удалял все остальное.

Я знаю, как просто тянуть в данных и обрабатывать его в любом языке я хочу затем удалить записи с огромным IN (...) query, но кажется, что лучшей альтернативой будет использовать SQL напрямую (я не прав?)

Я пробовал несколько запросов, но я не очень хорошо разбираюсь в SQL за пределами JOIN.

Вот то, что я до сих пор:

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 предназначен только для Мин (время).

Информация, которую я нашел по этой конкретной проблеме, предназначена только для поиска последней записи дня, а не для каждой последней записи для наборов данных.

ВАЖНО: Я хочу, чтобы первый/последний запись для каждого DISTINCT(data1, data2) на каждый день, а не только первый/последний запись для каждого дня в таблице. Для каждого дня будет более двух записей.

Решение: мое решение благодаря Джонатану Даан и Гордон Линофф:

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

Может быть идентификаторы полагались на как последовательный?Значение id id всегда будет иметь дату/время, равное или до id 11? – Augwa

+0

По какой причине вы хотите удалить старые записи? Это связано с плохой производительностью запросов? Или использование дискового пространства? – Augwa

+0

@JonathanDahan они определенно не будут последовательными, так как записи удаляются. Но я думаю, что вы на самом деле означаете монотонное увеличение. Из того, что я могу сказать, mysql 'auto_increment' по умолчанию монотонно увеличивает значение, если id_a korylprince

ответ

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 
+0

Спасибо. Это имеет ту же проблему, что и ответ @Gordan Linoff: я получаю первую/последнюю запись каждого дня, а не последнюю запись для каждого отдельного набора данных за каждый день. Я добавил важное примечание внизу. – korylprince

+0

обновлено для рассмотрения data1 & 2. – Augwa

+0

Ваше решение не работает для меня точно, но концепция работает. Я не знал, что GROUP BY по всем ценностям - это все, что нужно. Благодарю. – korylprince

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); 

Таким образом, вы можете получить более подробную информацию, если вам когда-нибудь понадобится.

+0

Спасибо! Это устраняет проблему для получения как min, так и max, но по-прежнему имеет другую проблему: я получаю первую/последнюю запись каждого дня, а не последнюю запись для каждого отдельного набора данных за каждый день. – korylprince

Смежные вопросы