Como o SQL Delete pode ser excluído usando uma subconsulta

15

O código a seguir foi adicionado por um de nossos desenvolvedores para excluir registros duplicados da tabela:

DELETE  SubQuery

FROM
(
    SELECT  ID
            ,FK1
            ,FK2
            ,CreatedDateTime
            ,ROW_NUMBER() OVER(PARTITION BY FK1, FK2 ORDER BY CreatedDateTime) AS RowNumber

    FROM    Table
)
AS SubQuery

WHERE   RowNumber > 1

Ao revisar o código, presumi que ele não funcionaria, no entanto, testá-lo em nosso ambiente de teste (SQL 2014) mostra que funciona!

Como a SQL sabe resolver a subconsulta e excluir os registros table?

Greg
fonte

Respostas:

14

O que subqueryvocê tem no seu código é chamado de tabela derivada . Não é uma tabela base, mas uma tabela que "vive" durante o tempo em que a consulta é executada. Visualizações semelhantes (que também são chamadas de tabelas visualizadas ) - e nas versões recentes CTEs, que é outra, a quarta maneira de "definir" uma tabela dentro de uma consulta - elas são semelhantes a uma tabela de várias maneiras. Você pode selectdeles, pode usá-los em fromou joinpara outras tabelas (base ou não!).

Em alguns DBMS, (nem todos os DBMS implementaram isso da mesma maneira), essas tabelas / visualizações são atualizáveis . E significa "atualizáveis" que podemos também update, insertpara dentro ou deletea partir deles.

Existem restrições e isso é esperado. Imagine se subqueryfoi uma junção de 2 (ou 17 tabelas). O que deletesignificaria então? (de quais tabelas as linhas devem ser excluídas?) As visualizações atualizáveis ​​são um assunto muito complicado . Há um livro recente (2012), inteiramente sobre esse assunto, escrito por Chris Date, conhecido especialista em teoria relacional: View Updating and Relational Theory .

Quando a tabela derivada (ou visualização) é uma consulta muito simples, como ela possui apenas uma tabela base (possivelmente restrita por a WHERE) e não GROUP BY, então todas as linhas da tabela derivada correspondem a uma linha na tabela base subjacente; fácil * para atualizar, inserir ou excluir a partir deste.

Quando o código dentro da subconsulta é mais complexo, depende se as linhas da tabela / exibição derivada podem ser rastreadas / resolvidas para linhas de uma das tabelas base subjacentes.

Para o SQL Server, você pode ler mais no parágrafo atualizáveis Visualizações no MSDN: CREATE VIEW.

Visualizações atualizáveis

Você pode modificar os dados de uma tabela base subjacente por meio de uma exibição, desde que as seguintes condições sejam verdadeiras:

  • Todas as modificações, incluindo UPDATE, INSERTe DELETEdeclarações, colunas de referência deve partir de apenas uma tabela de base.

  • As colunas que estão sendo modificadas na visualização devem fazer referência direta aos dados subjacentes nas colunas da tabela. As colunas não podem ser derivadas de nenhuma outra maneira, como por exemplo:

  • Uma função de agregação: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR, e VARP.

  • Uma computação. A coluna não pode ser calculada a partir de uma expressão que usa outras colunas. As colunas que são formadas usando os operadores de conjunto UNION, UNION ALL, CROSSJOIN, EXCEPT, e INTERSECT quantidade de uma computação e também não são actualizáveis.

  • As colunas a ser modificado não são afectados por GROUP BY, HAVINGou DISTINCTcláusulas.

  • TOPnão é usado em nenhum lugar da declaração select_ da exibição junto com a WITH CHECK OPTIONcláusula

As restrições anteriores se aplicam a quaisquer subconsultas na FROMcláusula da exibição, assim como se aplicam à exibição em si. Geralmente, o Mecanismo de Banco de Dados deve ser capaz de rastrear de forma inequívoca as modificações da definição de visualização em uma tabela base.


Na verdade, deleteé mais fácil, menos complexo que update. O SQL Server precisa apenas das chaves primárias ou de alguma outra maneira de identificar quais linhas da tabela base devem ser excluídas. Pois update, há uma restrição adicional (bastante óbvia) de que não podemos atualizar uma coluna computada. Você pode tentar modificar sua consulta para fazer uma atualização. A atualização do CreatedDateTimeprovavelmente funcionará bem, mas a tentativa de atualizar a RowNumbercoluna computada gerará um erro. E inserté ainda mais complexo, pois precisaríamos fornecer valores para todas as colunas da tabela base que não têm DEFAULTrestrição.

ypercubeᵀᴹ
fonte
4

É fácil ver quando você olha para o plano de consulta. No seu caso, o plano contém apenas um operador adicional de Projeto de Segmento e Sequência para manipular o número da linha. Esse tipo de operação funciona apenas quando o SQL Server realmente pode resolver a tabela subjacente.

A exclusão de subconsultas e CTEs é totalmente suportada e muito eficiente, principalmente para remover duplicatas. Também me lembro de usá-lo em versões mais antigas do SQL Server.

Mais em um post antigo do meu blog .

Daniel Hutmacher
fonte