Extraia apenas o primeiro da unidade de registro em que o valor da coluna especificada é duplicado

Página atualizada :
Data de criação de página :

Normalmente, ao extrair apenas um registro duplicado, a primeira coisa que vem à mente é distinct que eu penso, distinct não permite que você especifique uma coluna duplicada e outra coluna que você deseja recuperar ao mesmo tempo. Além disso,distinct não corresponde a esse requisito porque inclui registros não duplicados na extração.

Eu não acho que você pode entender o que você quer fazer apenas com o título, então vamos usar um registro de amostra como exemplo. O que eu quero fazer é o seguinte resultado de extração.

Nome do ID
1 Nome 1
2 Nome 2
3 Nome 3
3 Nome 3@example.com
4 Nome 4 Nome 4@example.com
4 Nome 4@example.com
4 Nome 4@example.com

Obtenha-o da seguinte maneira:

Nome do ID
3 Nome 3@example.com
4 Nome 4@example.com

Os IDs 1 e 2 não são incluídos porque não são duplicados. Os IDs 3 e 4 são duplicados, portanto, um deles é recuperado. No entanto, desta vez, não obteremos o primeiro registro na ordem de armazenamento do banco de dados. Além disso, suponha que você queira a primeira linha do nome em ordem de prioridade sob as condições de que "Nome contém uma marca @" e "Nome tem um pequeno número de caracteres".

A condição acima pode ser obtida com o seguinte SQL. No entanto, estamos usando subconsultas e não verificamos o desempenho.

select
  *
from
  (select *, row_number() over(order by ID asc) as RowNum from SampleTable) tableMain
where tableMain.RowNum =
(
  select
    top(1) RowNum
  from
    (select *, row_number() over(order by ID asc) as RowNum from SampleTable) tableSub
  where
        tableMain.ID = tableSub.ID
    and exists ( 
      select
        *
      from
        SampleTable
      where
        tableSub.ID = ID
      having
        count(*) >= 2
    )
  order by
    case when charindex(N'@', Name) >= 1 then 0 else 1 end, len(Name)
)

As linhas duplicadas são having verificadas com e count . group by A coluna de chave a ser verificada de fora, aqui ID a coluna é where reduzida por .

A ordem de precedência para recuperar a primeira linha é order by especificada por . charindex Aqui, e len verifique se ele contém o caractere especificado e o comprimento da string. top Tudo o que você precisa fazer é obter a primeira linha de cada registro duplicado em .

Originalmente, isso é bom, mas se houver dois ou mais registros com exatamente o mesmo valor, como "ID: 4, Nome: Nome 4@example.com", você inevitavelmente obterá dois registros. row_number Portanto, ele é anexado para que possa ser identificado para cada linha com , para que apenas um registro com exatamente o mesmo valor possa ser recuperado. Se for sabido que exatamente o mesmo registro não existe, row_number acho que seria melhor verificar os valores dos registros existentes sem anexar .

Se houver várias chaves a serem verificadas quanto a duplicatas, você poderá aumentar o número de colunas de chave para cada uma. Por exemplo, considere o seguinte registro: As colunas a serem verificadas quanto a duplicatas são "ID1" e "ID2".

ID1Nome ID2
1 1 Nome 1
2 1 Nome 2
3 1 Nome 31
3 2 Nome 32
4 1 Nome41
4 2 Nome42
4 2 Nome 4@example.com
5 1 Nome 555@example.com
5 1 Nome 55@example.com
5 2 Nome 5@example.com
6 1 Nome 6
6 1 Nome 66@example.com
6 2 Nome 6
6 2 Nome 6

O resultado da aquisição é o seguinte.

ID1Nome ID2
4 2 Nome 4@example.com
5 1 Nome 55@example.com
6 1 Nome 66@example.com
6 2 Nome 6

O SQL tem esta aparência: Você pode simplesmente aumentar a parte em que a coluna de chave foi especificada.

select
  *
from
  (select *, row_number() over(order by ID1 asc, ID2 asc) as RowNum from SampleTable) tableMain
where tableMain.RowNum =
(
  select
    top(1) RowNum
  from
    (select *, row_number() over(order by ID1 asc, ID2 asc) as RowNum from SampleTable) tableSub
  where
        tableMain.ID1 = tableSub.ID1
    and tableMain.ID2 = tableSub.ID2
    and exists ( 
      select
        *
      from
        SampleTable
      where
            tableSub.ID1 = ID1
        and tableSub.ID2 = ID2
      having
        count(*) >= 2
    )
  order by
    case when charindex(N'@', Name) >= 1 then 0 else 1 end, len(Name)
)