Удалить строки, сохранив одну из них с самой старой записью даты, используя SQL (MySQL) - PullRequest
2 голосов
/ 27 февраля 2020

У меня есть несколько миллионов строк в базе данных MySQL InnoDB, которые необходимо очистить. Посмотрите на этот пример.

SELECT archiveid, clearingid, pickdate 
  FROM tblclearingarchive 
  WHERE clearingid = 30978729 
  ORDER BY pickdate;


+-----------+------------+---------------------+
| archiveid | clearingid | pickdate            |
+-----------+------------+---------------------+
|  34328367 |   30978729 | NULL                | *
|  34333844 |   30978729 | 2015-10-27 15:55:30 | <- keep only this row with oldest date
|  34438038 |   30978729 | 2016-03-01 10:34:25 | *
|  34481472 |   30978729 | 2016-04-20 13:44:19 | *
+-----------+------------+---------------------+
4 rows in set (0.01 sec)

Итак, я знаю значение clearingid затронутых полей и хочу удалить поле без указания даты (ноль) и две строки, которые являются избыточными (позже, после первого выбора). В приведенном выше примере те, которые отмечены *, должны быть удалены.

Любые подсказки о том, как может выглядеть такое SQL обновление / удаление?

Есть около 30M строк и около 250K строк (известный clearingid's) для очистки.

Спасибо !!!

ОБНОВЛЕНИЕ:

С первоначальной идеей Матиаса Барра ios я нашел это решение для проверки. Он прекрасно отображает строки, которые я хочу удалить:

SELECT archiveid, clearingid, pickdate 
  FROM tblclearingarchive 
  WHERE clearingid = 30978729 
  AND (pickdate NOT IN (SELECT MIN(pickdate)
                        FROM tblclearingarchive 
                        WHERE clearingid = 30978729 ) 
       OR pickdate is NULL)
  ORDER BY pickdate;

+-----------+------------+---------------------+
| archiveid | clearingid | pickdate            |
+-----------+------------+---------------------+
|  34328367 |   30978729 | NULL                |
|  34438038 |   30978729 | 2016-03-01 10:34:25 |
|  34481472 |   30978729 | 2016-04-20 13:44:19 |
+-----------+------------+---------------------+
3 rows in set (0.20 sec)

Но я не могу удалить, используя такой запрос:

DELETE FROM tblclearingarchive 
  WHERE clearingid = 30978729 
  AND (pickdate NOT IN (SELECT MIN(pickdate)
                        FROM tblclearingarchive 
                        WHERE clearingid = 30978729 ) 
      OR pickdate is NULL);

ОШИБКА 1093 (HY000): Вы можете Не указывайте целевую таблицу «tblclearingarchive» для обновления в предложении FROM

Ответы [ 3 ]

1 голос
/ 27 февраля 2020

Вам нужно будет сделать это:

Создать «таблицу помощи», чтобы вы могли выполнить удаление

create table test as 
select * from tblclearingarchive

Затем выполните удаление:

delete from tblclearingarchive t1
where t1.pickdate <> (select min(t.pickdate) 
                     from test t
                     group by clearingid)
or t1.pickdate is null;

Вот небольшая демонстрация

1 голос
/ 27 февраля 2020

Если вы хотите первое, то вы можете отфильтровать:

select t.*
from t
where t.pickdate = (select min(t2.pickdate) 
                    from t t2
                    where t2.clearingid = t.clearingid
                   );

Или, если вы просто хотите одну строку:

select t.*
from t
where t.pickdate is not null
order by t.pickdate
limit 1;

РЕДАКТИРОВАТЬ:

Если вы хотите изменить таблицу:

delete t
    from t join
         (select clearingid, min(pickdate) as min_pickdate
          from t
          group by clearingid
         ) c
         on t.clearingid = c.clearingid
    where t.pickdate > c.min_pickdate or t.pickdate is null;
0 голосов
/ 27 февраля 2020

Это должно сделать, как вы намерены.

DELETE FROM tblclearingarchive
  WHERE archiveid IN (
    SELECT * FROM ( SELECT archiveid, clearingid, pickdate 
      FROM tblclearingarchive 
      WHERE clearingid = 30978729 
      AND pickdate NOT IN ( SELECT max(pickdate)
                        FROM tblclearingarchive LIMIT 1)
      ORDER BY pickdate) tmpTable
   ) OR  pickdate IS NULL

Дайте мне знать, если это работает.

...