如何删除 mysql 中的行,其中特定字段按时间顺序在另一个重复项旁边重复

How do I delete rows in mysql where a specific field is duplicated chronologically next to the other duplication

前言

我知道这里已经有许多 'delete duplicate row' 解决方案,但我觉得我的查询有很大差异,足以保证提出一个新问题。

背景

我的 table 作为所有产品价格点的历史档案,加班,按国家。它将无限期地保留历史数据。

我每天有一个 'price' 提要,其中包含 7 天的产品价格历史记录和 7 天的未来产品价格。数据包含 'country'、'product code' (sku)、'price' 和 'date from' 日期的价格。没有'date to';相关价格(在给定的一天)来自 'date from' 字段。

每天都会有很多重复的东西;由于大多数相同的数据日复一日地发送,并且给定的产品价格可能出现多达 14 次;因为它在 14 天内每天发送一次。我用 'sku_country_date_index' ('sku', 'country', 'date_from') 的 UNIQUE KEY 克服了这个问题——这可以防止这些类型的重复。

但是,发送系统并不是特别智能,并且经常发送价格变化数据,即使价格在上次记录的日期已经是那个价格,例如“2015-01-01 @ 10 英镑”,“2015-01-03 @ 10 英镑”。我想删除这些不必要的价格行。

此处发布的其他解决方案提供了有关删除完全重复行的信息;例如删除所有行,第一条,其中产品 X 的价格重复 - 这不是 suitable,因为价格会随着时间的推移而上下波动,并且可能在以后的日期具有相同的价格(价格之间的变化)。

问题

如何删除 mysql 中特定字段按时间顺序与另一个重复项相邻的行。

设置

Table:

CREATE TABLE IF NOT EXISTS `price` (
  `import_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `country` varchar(2) COLLATE utf8_bin DEFAULT NULL,
  `sku` varchar(7) COLLATE utf8_bin DEFAULT NULL,
  `date_from` date DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`import_id`),
  UNIQUE KEY `sku_country_date_index` (`sku`,`country`,`date_from`),
  KEY `sku_index` (`sku`),
  KEY `country_index` (`country`),
  KEY `date_from_index` (`date_from`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1;

示例数据:

REPLACE INTO `price`
(`country`, `sku`, `price`, `date_from`)
VALUES
('uk', '123', '10.00', '2015-01-01'),
('uk', '123', '11.00', '2015-01-04'),
('uk', '123', '9.00', '2015-01-06'),
('uk', '123', '9.00', '2015-01-09'),
('uk', '123', '9.00', '2015-01-13'),
('uk', '123', '10.00', '2015-01-16'),
('uk', '123', '9.00', '2015-01-20'),
('uk', '123', '10.00', '2015-01-25'),
('uk', '124', '10.00', '2015-01-06'),
('uk', '125', '10.00', '2015-01-06'),
('ie', '123', '10.00', '2015-01-06'),
('ie', '123', '14.00', '2015-01-07'),
('ie', '125', '10.00', '2015-01-06')

要求:

删除以下两行,因为它们不需要确定给定日期的产品价格 -

('uk', '123', '9.00', '2015-01-09'),
('uk', '123', '9.00', '2015-01-13'),

解决方案可以是 CREATE 或 REPLACE 语句的一部分 - 甚至是后续的 DELETE。

我的方法

供参考;以下是我采取的方法;不幸的是删除了太多行。它没有考虑如果中间有其他价格,则价格可以重复。

DELETE FROM `price` WHERE `import_id` IN (
  SELECT t1.import_id
  FROM `price` t1, `price` t2
  WHERE 1
  AND t1.date_from > t2.date_from
  AND t1.sku = t2.sku
  AND t1.price = t2.price
  AND t1.country = t2.country
)

因此,如果我没理解错的话,您希望在给定国家/地区、sku 和价格相同的一组记录的情况下,保留最低 import_id 的一行。

认为这会成功(警告,未经测试):

DELETE p2.*
FROM price p1
  INNER JOIN price p2
    ON p2.country = p1.country
       AND p2.sku = p1.sku
       AND p2.price = p1.price
       AND p2.import_id > p1.import_id;
delete d
  from t1 d 
    join t1 dd 
      on d.import_id = dd.import_id + 1 
      and d.sku = dd.sku 
      and d.price = dd.price 
      and d.country = dd.country

如果table未排序,我们可以使用上述解决方案中的想法来接收不需要的import_id

set @n:=0;
set @m:=0;
delete 
  from t1 
  where t1.import_id in (
     select d.import_id
        from  
           (select @n:=@n+1 AS row_number, import_id, country, sku, price, date_from 
              from t1 order by country, date_from) as d
              join 
                 (select @m:=@m+1 AS row_number, import_id,country, sku, price, date_from 
                    from t1 order by country, date_from) as dd 
              on d.row_number = dd.row_number + 1 
              and d.sku = dd.sku 
              and d.price = dd.price 
              and d.country = dd.country)