У меня есть таблица сопоставлений с единственным отличием от кортежа (c_id, t_id)
.
Вот несколько примеров данных, чтобы проиллюстрировать ситуацию:
id c_id t_id
----------------
1 10 2
2 10 3
3 10 7
4 12 2
5 13 3
Я написал функцию слияния для t_ids
(x, y → z OR x, y → x).
Если у моего контента (c_id
) есть и t_ids
, то я, конечно, нарушаю ограничение, используя этот оператор:
UPDATE mapping_table
SET t_id = '$target_tid'
WHERE t_id = '$t1_id' OR t_id = '$t2_id';
Результат:
id c_id t_id
----------------
1 10 4
2 10 4 /* violates unique constraint */
3 10 7
Теперь я придумал следующее:
/* delete one of the duplicate entries */
DELETE FROM mapping_table
WHERE ( SELECT count(c_id)
FROM mapping_table
WHERE t_id = '$t1_id' OR t_id = '$t2_id'
) > 1;
/* update the remaining row */
UPDATE mapping_table
SET t_id = '$target_tid'
WHERE t_id = '$t1_id' OR t_id = '$t2_id';
Теперь я получаю следующую ошибку: You can't specify target table 'mapping_table' for update in FROM clause
Мои вопросы:
DELETE
замеченным как обновление и не может использоваться в предложении WHERE
?Ошибка, с которой вы сталкиваетесь, является особенностью MySQL. Вы можете обойти это с помощью двойного набора подзапросов:
DELETE FROM mapping_table
WHERE (select *
from ( SELECT count(c_id)
FROM mapping_table
WHERE t_id = '$t1_id' OR t_id = '$t2_id'
) > 1
) t
Чтобы устранить проблему, просто удалите все идентификаторы, за исключением минимума. Я думаю, что это также может работать:
delete from mapping_table
where id > (select minid from (select min(id) from mapping_table mt2
where mt2.c_id = mapping_table.c_id and
mt2.t_id = mapping_table.t_id
)
)
Вы также можете сохранить список идентификаторов во временной таблице и использовать это в запросе:
create temporary table minids as
select c_id, t_id, min(id) as minid
from mapping_table
group by c_id, t_id;
delete from mapping_table
where exists (select 1 from minids
where mt2.c_id = mapping_table.c_id and
mt2.t_id = mapping_table.t_id and
mt2.minid > mapping_table.id
)
Я искал это решение. Производительность, вероятно, удивительно низкая, но, по крайней мере, я нашел рабочее решение (и узнал что-то).
/* actually delete rows that will become duplicate after the update */
DELETE FROM mt1 USING mapping_table AS mt1 WHERE id IN (
/* sub-query to allow `mapping_table` in the DELETE statement */
SELECT * FROM (
/* select ids/rows with one t_id available */
SELECT id
FROM mapping_table AS mt2
WHERE mt2.tag_id = $t1_id AND c_id IN (
/* select ids/rows with both t_id available */
SELECT c_id
FROM mapping_table AS mt3
WHERE mt3.c_id = mt2.c_id AND mt3.tag_id = $t2_id)
/* alias needed for every derived table */
) as mres
)
/* Update to merge t_ids */
UPDATE mapping_table
SET t_id = '$target_id'
WHERE t_id = '$t1_id' OR t_id = '$t2_id';
Попробуйте это
DELETE FROM mapping_table
WHERE ( SELECT count(c_id)
FROM mapping_table
WHERE t_id = '$t1_id' OR t_id = '$t2_id'
Having count(c_id) > 1
);
EDIT:
попробуйте это в своем статусе обновления
UPDATE mapping_table
SET t_id = '$target_tid'
WHERE t_id in (select t_id from mapping_table where t_id= '$t1_id' OR t_id = '$t2_id')
You can't specify target table 'mapping_table' for update in FROM clause