Извлекаем только первый из единиц записи, в которых дублируется значение указанного столбца
Обычно, когда извлекается только одна дублирующаяся запись, первое, что приходит на ум, это distinct
то, что я думаю:
distinct
Не позволяет указать дублирующийся столбец и еще один столбец, который вы хотите получить одновременно.
Кроме того, не соответствует этому требованию,distinct
поскольку включает в себя неповторяющиеся записи при извлечении.
Я не думаю, что вы можете понять, что вы хотите сделать только с названием, поэтому давайте возьмем образец записи в качестве примера. Я хочу получить следующий результат экстракции.
Имя удостоверения личности | |
---|---|
1 | Имя 1 |
2 | Имя 2 |
3 | Название 3 |
3 | Название 3@example.com |
4 | Имя 4 Имя 4@example.com |
4 | Название 4@example.com |
4 | Название 4@example.com |
Получится это следующим образом:
Имя удостоверения личности | |
---|---|
3 | Название 3@example.com |
4 | Название 4@example.com |
Идентификаторы 1 и 2 не включены, так как они не являются дубликатами. Идентификаторы 3 и 4 являются дубликатами, поэтому один из них извлекается. Однако на этот раз мы не получим первую запись в заказе на хранение БД. Кроме того, предположим, что вы хотите использовать первую строку имени в порядке приоритета при условии, что «Имя содержит знак @» и «Имя имеет небольшое количество символов».
Вышеуказанное условие может быть получено с помощью следующего SQL. Однако мы используем подзапросы и не проверяли производительность.
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)
)
Повторяющиеся строки проверяются having
с помощью и count
. group by
Ключевой столбец проверяется снаружи, здесь ID
столбец сужается where
вниз на .
Порядок приоритета для получения первой строки order by
задается с помощью . charindex
Здесь и len
проверяем, содержит ли он указанный символ и длину строки.
top
Все, что вам нужно сделать, это получить первую строку каждой повторяющейся записи в .
Изначально это нормально, но если есть две или более записей с точно таким же значением, например, "ID: 4, Name: Name 4@example.com", вы неизбежно получите две записи.
row_number
Следовательно, он добавляется таким образом, чтобы его можно было идентифицировать для каждой строки с помощью , чтобы можно было получить только одну запись с точно таким же значением.
Если известно, что точно такой же записи не существует, я row_number
думаю, что было бы лучше проверить значения существующих записей без добавления .
Если есть несколько ключей, которые необходимо проверить на наличие дубликатов, вы можете увеличить количество столбцов ключей для каждого из них. Например, рассмотрим следующую запись: Столбцы, которые должны быть проверены на наличие дубликатов, — это «ID1» и «ID2».
ID1 | ID2 | Имя |
---|---|---|
1 | 1 | Имя 1 |
2 | 1 | Имя 2 |
3 | 1 | Имя и фамилия 31 |
3 | 2 | Имя и фамилия 32 |
4 | 1 | Имя41 |
4 | 2 | Имя42 |
4 | 2 | Название 4@example.com |
5 | 1 | Название 555@example.com |
5 | 1 | Название 55@example.com |
5 | 2 | Название 5@example.com |
6 | 1 | Имя и фамилия 6 |
6 | 1 | Название 66@example.com |
6 | 2 | Имя и фамилия 6 |
6 | 2 | Имя и фамилия 6 |
Результат приобретения следующий.
ID1 | ID2 | Имя |
---|---|---|
4 | 2 | Название 4@example.com |
5 | 1 | Название 55@example.com |
6 | 1 | Название 66@example.com |
6 | 2 | Имя и фамилия 6 |
SQL выглядит следующим образом: Можно просто увеличить ту часть, где был указан ключевой столбец.
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)
)