Ошибка MySQL 1093: невозможно указать целевую таблицу для обновления в предложении FROM

StackOverflow https://stackoverflow.com/questions/45494

Вопрос

у меня есть стол 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.

Как я могу это преодолеть?

Это было полезно?

Решение

Обновлять:Этот ответ охватывает общую классификацию ошибок.Для более конкретного ответа о том, как лучше всего обрабатывать точный запрос ОП, см. другие ответы на этот вопрос.

В MySQL вы не можете изменить ту же таблицу, которую используете в части SELECT.
Такое поведение описано по адресу: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, перефразировано и расширено здесь.

Другие советы

НексусРекс предоставил очень хорошее решение для удаления с объединением из той же таблицы.

Если вы сделаете это:

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)

[обновить или удалить или что-то еще]

Это то, что я сделал для обновления значения столбца Priority на 1, если оно >=1 в таблице и в предложении WHERE, используя подзапрос к той же таблице, чтобы убедиться, что хотя бы одна строка содержит Priority=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;

Это быстро.Чем больше данных, тем лучше.

Самый простой способ сделать это — использовать псевдоним таблицы, когда вы ссылаетесь на родительскую таблицу запроса внутри подзапроса.

Пример :

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;

Попробуйте сохранить результат оператора Select в отдельной переменной, а затем использовать его для запроса на удаление.

как насчет этого запроса, надеюсь, он поможет

DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top