Erro MySQL 1093 - Não é possível especificar a tabela de destino para atualização na cláusula FROM
-
09-06-2019 - |
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?
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