З одиниці запису витягти тільки перший, де дублюється значення вказаного стовпця

Сторінка оновлюється :
Дата створення сторінки :

Зазвичай, коли ви витягуєте лише один дублікат запису, перше, що спадає на думку, це 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 не включені, оскільки вони не є дублікатами. ID 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".

Ім'я ID1ID2
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

Результат придбання виглядає наступним чином.

Ім'я ID1ID2
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)
)