Extraia apenas o primeiro da unidade de registro em que o valor da coluna especificada é duplicado
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".
| ID1 | Nome 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.
| ID1 | Nome 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)
)