Estrai solo il primo dall'unità di record in cui viene duplicato il valore della colonna specificata
Normalmente, quando si estrae un solo record duplicato, la prima cosa che viene in mente è distinct
che penso:
distinct
non consente di specificare contemporaneamente una colonna duplicata e un'altra colonna che si desidera recuperare.
Inoltre,distinct
non soddisfa questo requisito perché include record non duplicati nell'estrazione.
Non credo che tu possa capire cosa vuoi fare con il titolo da solo, quindi usiamo un record di esempio come esempio. Quello che voglio fare è il seguente risultato di estrazione.
Nome | 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 |
Ottenilo come segue:
Nome | ID |
---|---|
3 | Nome 3@example.com |
4 | Nome 4@example.com |
Gli ID 1 e 2 non sono inclusi perché non sono duplicati. Gli ID 3 e 4 sono duplicati, quindi uno di essi viene recuperato. Tuttavia, questa volta, non otterremo il primo record nell'ordine di archiviazione del database. Inoltre, supponiamo di volere la prima riga del nome in ordine di priorità nelle condizioni in cui "Il nome contiene un segno @" e "Il nome ha un numero ridotto di caratteri".
La condizione di cui sopra può essere ottenuta con il seguente SQL. Tuttavia, stiamo utilizzando le sottoquery e non abbiamo controllato le prestazioni.
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)
)
Le righe duplicate vengono having
controllate con e count
. group by
La colonna chiave da controllare dall'esterno, qui ID
la colonna è where
ristretta di .
L'ordine di precedenza per il recupero della prima riga è order by
specificato da . charindex
Qui, e len
controlla se contiene il carattere specificato e la lunghezza della stringa.
top
Tutto quello che devi fare è ottenere la prima riga di ogni record duplicato in .
Originariamente, questo va bene, ma se ci sono due o più record con esattamente lo stesso valore, come "ID: 4, Nome: Nome 4@example.com", otterrai inevitabilmente due record.
row_number
Pertanto, viene aggiunto in modo che possa essere identificato per ogni riga con , in modo che sia possibile recuperare un solo record con esattamente lo stesso valore.
Se si sa che lo stesso identico record non esiste, penso row_number
che sarebbe meglio controllare i valori dei record esistenti senza aggiungere .
Se sono presenti più chiavi da verificare la presenza di duplicati, è possibile aumentare il numero di colonne chiave per ciascuna. Si consideri, ad esempio, il seguente record: Le colonne da verificare la presenza di duplicati sono "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 |
Il risultato dell'acquisizione è il seguente.
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 |
L'SQL è simile al seguente: È possibile aumentare semplicemente la parte in cui è stata specificata la colonna chiave.
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)
)