MySQL Error 1093-не может указать целевую таблицу для обновления в предложении FROM
у меня есть таблица story_category
в моей базе данных с поврежденных записей. Следующий запрос возвращает поврежденные записи:
SELECT *
FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id);
Я попытался удалить их выполнение:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category
INNER JOIN story_category ON category_id=category.id);
но я получаю следующую ошибку:
#1093 - вы не можете указать целевую таблицу "story_category" для обновления в предложении FROM
как я могу преодолеть это?
14 ответов
Update: этот ответ охватывает общую классификацию ошибок. Для более конкретного ответа о том, как лучше всего обрабатывать точный запрос OP, см. другие ответы на этот вопрос
в MySQL вы не можете изменить ту же таблицу, которую вы используете в выбранной части.
Это поведение задокументировано на:
http://dev.mysql.com/doc/refman/5.6/en/update.html
возможно, вы можете просто присоединиться к столу, чтобы сам
если логика достаточно проста, чтобы переформулировать запрос, потеряйте подзапрос и присоедините таблицу к себе, используя соответствующие критерии выбора. Это заставит MySQL видеть таблицу как две разные вещи, позволяя деструктивным изменениям идти вперед.
UPDATE tbl AS a
INNER JOIN tbl AS b ON ....
SET a.col = b.col
кроме того, попробуйте вложить подзапрос глубже в предложение from ...
если вы абсолютно нужен подзапрос, есть обходной путь, но это некрасиво несколько причин, в том числе:
UPDATE tbl SET col = (
SELECT ... FROM (SELECT.... FROM) AS x);
вложенный подзапрос в предложении FROM создает неявные временные таблица, поэтому он не считается той же таблицей, которую вы обновляете.
... но следите за оптимизатором запросов
однако, остерегайтесь этого от MySQL 5.7.6 и далее, оптимизатор может оптимизировать подзапрос и все равно дать вам ошибку. К счастью,optimizer_switch
переменная может использоваться для переключения от этого поведения; хотя я не мог бы рекомендовать делать это как что-то большее, чем краткосрочное исправление или для небольших одноразовых задач.
SET optimizer_switch = 'derived_merge=off';
спасибо Петер В. Мерх для этого совета в комментариях.
пример техники был от Барона Шварца,первоначально опубликовано в Nabble, перефразировано и расширено здесь.
NexusRex предоставил очень хорошее решение для удаления с помощью join из той же таблицы.
Если вы это сделаете:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id AS cid FROM category
INNER JOIN story_category ON category_id=category.id
)
вы получите сообщение об ошибке.
но если вы обернете условие еще одним выбором:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT cid FROM (
SELECT DISTINCT category.id AS cid FROM category
INNER JOIN story_category ON category_id=category.id
) AS c
)
это было бы правильно!!
объяснение: оптимизатор запросов делает оптимизация производного слияния для первого запроса (что приводит к сбою с ошибкой), но второй запрос не подходит для оптимизация производного слияния. Следовательно, оптимизатор вынужден сначала выполнить подзапрос.
на inner join
в вашем подзапросе нет необходимости. Похоже, вы хотите удалить записи в story_category
здесь category_id
не в category
таблица.
этого:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category);
вместо этого:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id);
недавно мне пришлось обновлять записи в той же таблице, что и ниже:
UPDATE skills AS s, (SELECT id FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development'
WHERE s.id = p.id;
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT cid FROM (
SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id
) AS c
)
Если вы не можете сделать
UPDATE table SET a=value WHERE x IN
(SELECT x FROM table WHERE condition);
потому что это одна и та же таблица, вы можете обмануть и сделать:
UPDATE table SET a=value WHERE x IN
(SELECT * FROM (SELECT x FROM table WHERE condition) as t)
[обновить или удалить или что угодно]
Это то, что я сделал для обновления значения столбца приоритета на 1, если это >=1 в таблице и в его предложении WHERE, используя подзапрос в той же таблице, чтобы убедиться, что по крайней мере одна строка содержит приоритет=1 (потому что это условие должно быть проверено при выполнении обновления) :
UPDATE My_Table
SET Priority=Priority + 1
WHERE Priority >= 1
AND (SELECT TRUE FROM (SELECT * FROM My_Table WHERE Priority=1 LIMIT 1) as t);
Я знаю, что это немного уродливо, но он работает нормально.
вы можете вставить нужные строки идентификаторов во временную таблицу, а затем удалить все строки, которые находятся в этой таблице.
Что может быть тем, что @Cheekysoft имел в виду, делая это в два шага.
по данным синтаксис обновления Mysql связанный @CheekySoft, он говорит прямо внизу.
в настоящее время, вы не можете обновить таблицу и выбрать из той же таблицы в подзапросе.
Я думаю, вы удаляете из store_category, все еще выбирая из него в Союзе.
если что-то не работает, проходя через парадную дверь, тогда возьмите заднюю дверь:
drop table if exists apples;
create table if not exists apples(variety char(10) primary key, price int);
insert into apples values('fuji', 5), ('gala', 6);
drop table if exists apples_new;
create table if not exists apples_new like apples;
insert into apples_new select * from apples;
update apples_new
set price = (select price from apples where variety = 'gala')
where variety = 'fuji';
rename table apples to apples_orig;
rename table apples_new to apples;
drop table apples_orig;
это быстро. Чем больше данных, тем лучше.
попробуйте сохранить результат оператора Select в отдельной переменной, а затем использовать его для запроса удаления.
Как насчет этого запроса надеюсь, что это поможет
DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL
самый простой способ сделать это-использовать псевдоним таблицы, когда вы ссылаетесь на таблицу родительского запроса внутри подзапроса.
пример :
insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));
меняем его на:
insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P));
попробуй такое
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM (SELECT * FROM STORY_CATEGORY) sc;