mysql - 将除 1 条匹配多个字段(几乎重复)的记录之外的所有记录标记为已删除

mysql - mark all but 1 records matching multiple fields (near duplicates) as deleted

我有一个 mysql table 用于购物车中的商品。 我需要将相同项目的任何重复项标记为已删除(通过在 'deleted' 列中输入时间戳,而不是出于审计跟踪原因实际删除)。

table(order_item)的列是:

id (int, primary key)
order_id (int)
type (enum)
item_id* (int)
timeslot_id* (int)
price_id* (int)
created (datetime)
deleted (datetime)

我想更新 table 中除 1 项之外的所有重复项目(与另一行具有相同的值),以便为标有 * 的列上的订单更新当前日期时间删除的列。这样一次只能购买一件相同的产品。

我目前通过使用 GROUP BY 和 ID 计数进行 select 查询并使用 Concat 获取以逗号分隔的 ID 列表 - 然后在一个单独的查询。

SELECT COUNT(id) AS c, 
GROUP_CONCAT(DISTINCT id SEPARATOR ",") AS ids 
FROM cps_order_item WHERE order_id = "10" 
AND deleted = "0000-00-00 00:00:00" 
GROUP BY type, item_id, timeslot_id, price_id;

有什么可靠的方法可以在一次查询中完成所有这些操作?

我认为您可以通过更新和自连接来实现逻辑:

update order_item oi
inner join (
    select order_id, item_id, timeslot_id, price_id, min(id) as id
    from order_item
    where deleted = '0000-00-00 00:00:00'
    group by order_id, item_id, timeslot_id, price_id
) oi1 
    on  oi1.order_id    = oi.order_id
    and oi1.item_id     = oi.item_id
    and oi1.timeslot_id = oi.timeslot_id
    and oi1.price_id    = oi.price_id
    and oi1.id <> oi.id
set oi.deleted = now()
where oi.deleted = '0000-00-00 00:00:00'

子查询计算每个值元组的最小值 id。然后外部查询为在元组上匹配且其 id 不是最小值的行设置列 deleted

这一次处理所有订单。您可以在外部查询的 where 子句中添加一个过滤器以仅处理一个订单。如果您愿意,您也可以将聚合函数更改为其他函数(也许您想要 max(id) 而不是 min(id))。

注意:此解决方案 不适用于 MySQL。请参阅下面的评论。我留下它希望它可以帮助将来使用其他 RDBMS 的人。

只需删除同一订单中创建日期晚于您正在考虑的订单的商品。我不太确定 MySQL 语法,但看起来像:

UPDATE order_item o
SET deleted = NOW()
WHERE deleted = '0000-00-00 00:00:00'
  AND order_id = 10
  AND EXISTS (
    SELECT *
    FROM order_item
    WHERE order_id = o.order_id
      AND item_id = o.item_id
      AND type = o.type
      AND timeslot_id = o.timeslot_id
      AND price_id = o.price_id
      AND deleted = o.deleted
      AND created > o.created
  );

我使用了与您提供的查询相同的约束条件。

您可能需要删除 AND ORDER = ID 行以一次性清除所有订单。

也许 price_id、type 和 timeslot_id 的约束是不必要的(假设项目 id 暗示了这些属性)。