Erro MySQL 1093 - Não é possível especificar a tabela de destino para atualização na cláusula FROM

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

Pergunta

eu tenho uma mesa story_category no meu banco de dados com entradas corrompidas.A próxima consulta retorna as entradas corrompidas:

SELECT * 
FROM  story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
       story_category ON category_id=category.id);

Tentei excluí-los executando:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category 
      INNER JOIN story_category ON category_id=category.id);

Mas recebo o próximo erro:

#1093 - Você não pode especificar a tabela de destino 'story_category' para atualização na cláusula FROM

Como posso superar isso?

Foi útil?

Solução

Atualizar:Esta resposta cobre a classificação geral de erros.Para obter uma resposta mais específica sobre como lidar melhor com a consulta exata do OP, consulte outras respostas a esta pergunta

No MySQL, você não pode modificar a mesma tabela usada na parte SELECT.
Esse comportamento está documentado em:http://dev.mysql.com/doc/refman/5.6/en/update.html

Talvez você possa simplesmente juntar a mesa a ela mesma

Se a lógica for simples o suficiente para remodelar a consulta, perca a subconsulta e junte a tabela a si mesma, empregando critérios de seleção apropriados.Isso fará com que o MySQL veja a tabela como duas coisas diferentes, permitindo que mudanças destrutivas ocorram.

UPDATE tbl AS a
INNER JOIN tbl AS b ON ....
SET a.col = b.col

Alternativamente, tente aninhar a subconsulta mais profundamente em uma cláusula from ...

Se você precisar absolutamente da subconsulta, há uma solução alternativa, mas é feio por vários motivos, incluindo desempenho:

UPDATE tbl SET col = (
  SELECT ... FROM (SELECT.... FROM) AS x);

A subconsulta aninhada na cláusula FROM cria um Tabela temporária implícita, portanto não conta como a mesma tabela que você está atualizando.

...mas cuidado com o otimizador de consulta

No entanto, tome cuidado para que a partir de MySQL 5.7.6 em diante, o otimizador pode otimizar a subconsulta e ainda assim apresentar o erro.Felizmente, o optimizer_switch variável pode ser usada para desligar esse comportamento;embora eu não pudesse recomendar fazer isso como algo mais do que uma solução de curto prazo ou para pequenas tarefas únicas.

SET optimizer_switch = 'derived_merge=off';

Graças a Pedro V.Morch para este conselho nos comentários.

A técnica de exemplo foi do Barão Schwartz, publicado originalmente em Nabble, parafraseado e ampliado aqui.

Outras dicas

NexusRex forneceu um solução muito boa para excluir com join da mesma tabela.

Se você fizer isto:

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
)

você receberá um erro.

Mas se você envolver a condição em mais uma seleção:

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
)

faria a coisa certa!!

Explicação: O otimizador de consulta faz uma otimização de mesclagem derivada para a primeira consulta (o que causa falha com o erro), mas a segunda consulta não se qualifica para o otimização de mesclagem derivada.Conseqüentemente, o otimizador é forçado a executar a subconsulta primeiro.

O inner join na sua subconsulta é desnecessária.Parece que você deseja excluir as entradas em story_category onde o category_id não está no category mesa.

Fazem isto:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category);

Ao invés disso:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN
         story_category ON category_id=category.id);

Recentemente tive que atualizar registros na mesma tabela que fiz abaixo:

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
)

Se você não pode fazer

UPDATE table SET a=value WHERE x IN
    (SELECT x FROM table WHERE condition);

porque é a mesma tabela, você pode enganar e fazer:

UPDATE table SET a=value WHERE x IN
    (SELECT * FROM (SELECT x FROM table WHERE condition) as t)

[atualizar ou excluir ou qualquer outra coisa]

Isto é o que fiz para atualizar o valor de uma coluna Prioridade em 1 se for >=1 em uma tabela e em sua cláusula WHERE usando uma subconsulta na mesma tabela para garantir que pelo menos uma linha contenha Prioridade=1 (porque essa era a condição a ser verificada durante a atualização):


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);

Eu sei que é um pouco feio, mas funciona bem.

Você pode inserir os IDs das linhas desejadas em uma tabela temporária e, em seguida, excluir todas as linhas encontradas nessa tabela.

que pode ser o que @Cheekysoft quis dizer ao fazer isso em duas etapas.

De acordo com a sintaxe UPDATE do Mysql vinculado por @CheekySoft, está escrito logo abaixo.

Atualmente, não é possível atualizar uma tabela e selecionar na mesma tabela em uma subconsulta.

Eu acho que você está excluindo store_category enquanto ainda seleciona na união.

Se algo não funcionar, ao passar pela porta da frente, vá pela porta dos fundos:

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;

É rápido.Quanto maiores os dados, melhor.

A maneira mais simples de fazer isso é usar um alias de tabela ao referir-se à tabela de consulta pai dentro da subconsulta.

Exemplo :

insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));

Altere para:

insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P));

tente isso

DELETE FROM story_category 
WHERE category_id NOT IN (
SELECT DISTINCT category.id 
FROM (SELECT * FROM STORY_CATEGORY) sc;

Tente salvar o resultado da instrução Select em uma variável separada e use-a para a consulta de exclusão.

que tal esta consulta espero que ajude

DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top