Извлекаем только первый из единиц записи, в которых дублируется значение указанного столбца

Страница обновлена :
Дата создания страницы :

Обычно, когда извлекается только одна дублирующаяся запись, первое, что приходит на ум, это 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)
)