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 não funcionaria, no entanto, testá-lo em nosso ambiente de teste (SQL 2014) mostra que sim!
Como o SQL sabe resolver a subconsulta e excluir os registros table
?
O
subquery
que você tem em 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. Como visualizações (que também são chamadas de tabelas visualizadas ) - e em versões recentes CTEs que é outra, 4ª maneira de "definir" uma tabela dentro de uma consulta - elas são semelhantes a uma tabela de várias maneiras. Você podeselect
a partir deles, você pode usá-los emfrom
ou parajoin
eles em outras tabelas (base ou não!).Em alguns DBMS (nem todos os DBMS implementaram isso da mesma maneira), essas tabelas/visões são atualizáveis .
update
E "atualizável" significa que também podemosinsert
entrar oudelete
sair deles.No entanto, existem restrições e isso é esperado. Imagine se
subquery
fosse uma junção de 2 (ou 17 tabelas). O quedelete
significaria então? (de quais tabelas as linhas devem ser excluídas?) Visualizações atualizáveis é um assunto muito complicado . Existe um livro recente (2012), inteiramente sobre este assunto, escrito por Chris Date, conhecido especialista em teoria relacional: View Updating and Relational Theory .Quando a tabela derivada (ou exibição) é uma consulta muito simples, como se tivesse apenas uma tabela base (possivelmente restrita por um
WHERE
) e nenhumGROUP BY
, então cada linha da tabela derivada corresponde a uma linha na tabela base subjacente, então é fácil * para atualizar, inserir ou excluir disso.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 SQL Server, você pode ler mais no parágrafo Updatable Views no MSDN:
CREATE VIEW
.Na verdade
delete
é mais fácil, menos complexo do queupdate
. O SQL Server precisa apenas das chaves primárias ou de alguma outra forma de identificar quais linhas da tabela base devem ser excluídas. Paraupdate
, 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çãoCreatedDateTime
provavelmente funcionará bem, mas tentar atualizar aRowNumber
coluna computada gerará um erro. Einsert
é ainda mais complexo, pois teríamos que fornecer valores para todas as colunas da tabela base que não possuemDEFAULT
restrição.É fácil ver quando você olha para o plano de consulta. No seu caso, o plano contém apenas um operador Segmento e Projeto de Sequência adicional para lidar com o número da linha. Esse tipo de operação só funciona quando o SQL Server realmente pode resolver a tabela subjacente.
A exclusão de subconsultas e CTEs é totalmente suportada e muito eficiente, especialmente para remover duplicatas. Também me lembro de usá-lo em versões mais antigas do SQL Server.
Mais em um antigo post meu no blog.