Eu tenho uma tabela 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);
Eu 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 eu 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?
mysql
subquery
sql-delete
mysql-error-1093
Sergio del Amo
fonte
fonte
Respostas:
Atualização: 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 que você usa 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 si próprio
Se a lógica for simples o suficiente para remodelar a consulta, perca a subconsulta e junte a tabela a ela 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.
Como alternativa, tente aninhar a subconsulta mais profundamente na cláusula from ...
Se você absolutamente precisa da subconsulta, há uma solução alternativa, mas é feia por vários motivos, incluindo desempenho:
A subconsulta aninhada na cláusula FROM cria uma tabela temporária implícita , portanto não conta como a mesma tabela que você está atualizando.
... mas cuidado com o otimizador de consultas
No entanto, tenha cuidado com o MySQL 5.7.6 em diante, o otimizador pode otimizar a subconsulta e ainda assim fornecer o erro. Felizmente, a
optimizer_switch
variável pode ser usada para desativar esse comportamento; embora eu não possa recomendar fazer isso como algo além de uma correção de curto prazo ou para pequenas tarefas pontuais.Obrigado a Peter V. Mørch por esse conselho nos comentários.
A técnica de exemplo foi do Barão Schwartz, originalmente publicada em Nabble , parafraseada e estendida aqui.
fonte
SET optimizer_switch = 'derived_merge=off';
:-(O NexusRex forneceu uma solução muito boa para excluir com junção da mesma tabela.
Se você fizer isto:
você receberá um erro.
Mas se você agrupar a condição em mais uma, selecione:
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 no erro), mas a segunda consulta não se qualifica para a otimização de mesclagem derivada . Portanto, o otimizador é forçado a executar a subconsulta primeiro.
fonte
A
inner join
subconsulta é desnecessária. Parece que você deseja excluir as entradas emstory_category
quecategory_id
não estão nacategory
tabela.Faça isso:
Ao invés disso:
fonte
DISTINCT
é desnecessário aqui - para um melhor desempenho;).where in
na coluna ID, para que você não precise subconsultar a tabela principal.Recentemente, tive que atualizar registros na mesma tabela que fiz como abaixo:
fonte
UPDATE skills SET type='Development' WHERE type='Programming';
? Isso não parece estar respondendo à pergunta original.UPDATE skills SET type='Development' WHERE type='Programming';
. Eu não entendo por que tantas pessoas não está pensando sobre o que fazer ...fonte
UPDATE tbl AS a INNER JOIN tbl AS b ON .... SET a.col = b.col
- isso funcionaria como um apelido diferente para a mesma tabela que é usada aqui. Da mesma forma, na resposta do @ NexusRex, a primeiraSELECT
consulta atua como uma tabela derivada na qualstory_category
é usada pela segunda vez. Portanto, o erro mencionado no OP não deve ocorrer aqui, certo?Se você não pode fazer
porque é a mesma tabela, você pode enganar e fazer:
[atualizar ou excluir ou o que for]
fonte
Foi o que fiz para atualizar um valor da coluna Priority por 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 Priority = 1 (porque esse era o condição a ser verificada durante a atualização):
Eu sei que é um pouco feio, mas funciona bem.
fonte
A maneira mais simples de fazer isso é usar um alias de tabela quando você estiver consultando a tabela de consulta pai dentro da subconsulta.
Exemplo:
Altere para:
fonte
Você pode inserir os IDs das linhas desejadas em uma tabela temporária e excluir todas as linhas encontradas nessa tabela.
que pode ser o que a @Cheekysoft quis dizer com isso em duas etapas.
fonte
De acordo com o Mysql UPDATE Syntax, vinculado por @CheekySoft, está escrito na parte inferior.
Eu acho que você está excluindo da store_category enquanto ainda a seleciona na união.
fonte
Para a consulta específica que o OP está tentando realizar, a maneira ideal e mais eficiente de fazer isso é NÃO usar uma subconsulta.
Aqui estão as
LEFT JOIN
versões das duas consultas do OP:Nota:
DELETE s
restringe as operações de exclusão àstory_category
tabela.Documentação
fonte
UPDATE
instruções e subconsultas associadas. Permitindo que você executeLEFT JOIN ( SELECT ... )
o contrárioWHERE IN( SELECT ... )
, tornando a implementação útil em muitos casos de uso.Se algo não funcionar, ao passar pela porta da frente, pegue a porta dos fundos:
É rápido. Quanto maiores os dados, melhor.
fonte
Tente salvar o resultado da instrução Select em variável separada e use-o para excluir a consulta.
fonte
tente isso
fonte
que tal esta consulta espero que ajude
fonte
DELETE story_category FROM ...
no entanto, a subconsulta associada não é necessária nesse contexto e pode ser executada usandoLEFT JOIN category AS cat ON cat.id = story_category.category_id WHERE cat.id IS NULL
: Observe os critérios de associação na resposta incorretamente referenciastory_category.id = cat.id
No que diz respeito às preocupações, você deseja excluir as linhas
story_category
que não existemcategory
.Aqui está sua consulta original para identificar as linhas a serem excluídas:
Combinar
NOT IN
com uma subconsulta queJOIN
é a tabela original parece involuntariamente complicado. Isso pode ser expresso de uma maneira mais direta e comnot exists
uma subconsulta correlacionada:Agora é fácil transformar isso em uma
delete
declaração:Essa consulta seria executada em qualquer versão do MySQL, assim como na maioria dos outros bancos de dados que eu conheço.
Demo no DB Fiddle :
fonte