mysql n:m запрос на удаление отношения 1242 Подзапрос возвращает более 1 строки

У меня есть две таблицы SQL, "продукты" и "теги". Они имеют отношение n:m, используя третью таблицу 'product_tags'.

Я хочу удалить некоторые продукты и соответствующие теги вместе.

Допустим, у меня есть products.product_id=3, у этого продукта tags.tag_id=3, tags.tag_id=5

таблица product_tags

product_id 3 tag_id 3
product_id 3 tag_id 5

delete from tags where tag_id in (select product_tags.tag_id from product_tags where product_id =3);
delete from tags where tag_in = any (select product_tags.tag_id from product_tags where product_id=3);

либо будет производить

0 row(s) affected, 1 warning(s): 1242 Subquery returns more than 1 row

Итак, как я могу это сделать?

1 ответ

Решение

Прежде всего вы, скорее всего, захотите удалить теги, которые не используются с другими продуктами. Например, если тег с tag_id = 3 также используется с некоторым другим продуктом, скажем, product_id = 1 тогда вы не должны удалять этот тег.

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

При этом ваш код для безопасного удаления продукта вместе с неиспользованными тегами может выглядеть

DELIMITER //
CREATE PROCEDURE delete_product(IN _product_id INT)
BEGIN
  DROP TEMPORARY TABLE IF EXISTS tmp_tags_to_be_deleted;

  START TRANSACTION;

  CREATE TEMPORARY TABLE tmp_tags_to_be_deleted(tag_id INT PRIMARY KEY);
  INSERT INTO tmp_tags_to_be_deleted
  SELECT tag_id
    FROM product_tags t
   WHERE product_id = _product_id
     AND NOT EXISTS
  (
    SELECT *
      FROM product_tags
     WHERE tag_id = t.tag_id
       AND product_id <> t.product_id
  );

  DELETE 
    FROM product_tags
   WHERE product_id = _product_id;

  DELETE t
    FROM tags t JOIN tmp_tags_to_be_deleted x
      ON t.tag_id = x.tag_id;

  DELETE 
    FROM products
   WHERE product_id = _product_id;

  COMMIT;
END//
DELIMITER ;

Использование:

CALL delete_product(3);

Вот демоверсия SQLFiddle

Другие вопросы по тегам