Пошук повторюваних рядків у SQL Server


231

У мене база даних організацій SQL Server, і є багато повторюваних рядків. Я хочу запустити довідку select, щоб забрати все це та кількість копійок, а також повернути ідентифікатори, пов’язані з кожною організацією.

Заява на зразок:

SELECT     orgName, COUNT(*) AS dupes  
FROM         organizations  
GROUP BY orgName  
HAVING      (COUNT(*) > 1)

Поверне щось на кшталт

orgName        | dupes  
ABC Corp       | 7  
Foo Federation | 5  
Widget Company | 2 

Але я також хотів би схопити їхні посвідчення. Чи можна це зробити? Можливо, як

orgName        | dupeCount | id  
ABC Corp       | 1         | 34  
ABC Corp       | 2         | 5  
...  
Widget Company | 1         | 10  
Widget Company | 2         | 2  

Причина полягає в тому, що існує також окрема таблиця користувачів, що посилаються на ці організації, і я хотів би їх об'єднати (тому видаляйте дупи, щоб користувачі посилалися на ту саму організацію замість дуп-оргів). Але я хотів би розлучитися вручну, щоб я нічого не накручував, але мені все одно потрібна заява, що повертає ідентифікатори всіх орг-оргій, щоб я міг пройти список користувачів.

Відповіді:


313
select o.orgName, oc.dupeCount, o.id
from organizations o
inner join (
    SELECT orgName, COUNT(*) AS dupeCount
    FROM organizations
    GROUP BY orgName
    HAVING COUNT(*) > 1
) oc on o.orgName = oc.orgName

4
Чи є якісь обмеження в цьому запиті, наприклад, якщо кількість записів становить 10 мільйонів плюс?
Паровий

3
@Steam Ви праві: ця відповідь не є ефективною у більшій базі даних з мільйонами записів. Віддайте перевагу GroupBy / Маючи відповідь, подану Айкутом, яку можна краще оптимізувати за допомогою бази даних. Один виняток: я пропоную використовувати Count (0) замість Count (*) для спрощення речей.
Майк Крістіан

1
@Mike - чому Count (0) проти Count (*)?
KornMuffin

2
@KornMuffin В ретроспективі мій коментар щодо Count () недійсний. Використання ненульової оцінки в Count () корисно лише тоді, коли потрібно підрахувати ненульові результати, повернуті зовнішнім з'єднанням. В іншому випадку використовуйте Count (*). Велике пояснення можна знайти тут .
Майк Крістіан

використовувати isnull()для мінливих стовпців на onсекції
Аріф Улусой

92

Ви можете запустити наступний запит і знайти копії max(id)та видалити ці рядки.

SELECT orgName, COUNT(*), Max(ID) AS dupes 
FROM organizations 
GROUP BY orgName 
HAVING (COUNT(*) > 1)

Але вам доведеться запустити цей запит кілька разів.


Ви повинні запустити його рівно MAX( COUNT(*) ) - 1, що може бути здійсненим.
DerMike

1
привіт, це будь-який спосіб отримати всі ідентифікатори замість max id, як для 2, я можу використовувати max і min, але як щодо більше 2? @DerMike
Mukherjee

31

Ви можете це зробити так:

SELECT
    o.id, o.orgName, d.intCount
FROM (
     SELECT orgName, COUNT(*) as intCount
     FROM organizations
     GROUP BY orgName
     HAVING COUNT(*) > 1
) AS d
    INNER JOIN organizations o ON o.orgName = d.orgName

Якщо ви хочете повернути лише записи, які можна видалити (залишивши один з кожного), ви можете використовувати:

SELECT
    id, orgName
FROM (
     SELECT 
         orgName, id,
         ROW_NUMBER() OVER (PARTITION BY orgName ORDER BY id) AS intRow
     FROM organizations
) AS d
WHERE intRow != 1

Редагувати: SQL Server 2000 не має функції ROW_NUMBER (). Натомість ви можете використовувати:

SELECT
    o.id, o.orgName, d.intCount
FROM (
     SELECT orgName, COUNT(*) as intCount, MIN(id) AS minId
     FROM organizations
     GROUP BY orgName
     HAVING COUNT(*) > 1
) AS d
    INNER JOIN organizations o ON o.orgName = d.orgName
WHERE d.minId != o.id

Перше твердження працює, але друге, здається, не працює.
xtine

Схоже, SQL Server не може розпізнати row_number ()?
xtine

Ах ... у вас є старша версія SQL Server? Я вважаю, що він був представлений у SQL Server 2005.
Павло

3
дякую ще раз, кожен раз, коли мені потрібно це зробити, я приїжджаю сюди і
ЛЮБИТУ

9

Рішення, позначене як правильне, не працювало для мене, але я знайшов цю відповідь, яка працювала просто чудово: Отримайте список повторюваних рядків у MySql

SELECT n1.* 
FROM myTable n1
INNER JOIN myTable n2 
ON n2.repeatedCol = n1.repeatedCol
WHERE n1.id <> n2.id

У наборі результатів ви отримаєте багато пустушок, тож вам доведеться мати справу і з ними.
Ренан

1
Якщо ідентифікатор числовий, перевірка n1.id > n2.idзапобіжить появі кожної пари двічі.
голодував

9

Ви можете спробувати це, найкраще для вас

 WITH CTE AS
    (
    SELECT *,RN=ROW_NUMBER() OVER (PARTITION BY orgName ORDER BY orgName DESC) FROM organizations 
    )
    select * from CTE where RN>1
    go

будь-який спосіб отримати весь ідентифікатор у розбитті комами або різних стовпцях
Arijit Mukherjee

6

Якщо ви хочете видалити дублікати:

WITH CTE AS(
   SELECT orgName,id,
       RN = ROW_NUMBER()OVER(PARTITION BY orgName ORDER BY Id)
   FROM organizations
)
DELETE FROM CTE WHERE RN > 1

6
select * from [Employees]

Для пошуку дубліката Запису 1) Використання CTE

with mycte
as
(
select Name,EmailId,ROW_NUMBER() over(partition by Name,EmailId order by id) as Duplicate from [Employees]
)
select * from mycte

2) Використовуючи GroupBy

select Name,EmailId,COUNT(name) as Duplicate from  [Employees] group by Name,EmailId 

Це найшвидше рішення тут, коли ВИБІРІТЬ дані понад 10м рядків. Спасибі
Fandango68

4
Select * from (Select orgName,id,
ROW_NUMBER() OVER(Partition By OrgName ORDER by id DESC) Rownum
From organizations )tbl Where Rownum>1

Тож записи з rowum> 1 будуть дублюючими записами у вашій таблиці. "Розділіть" спочатку згрупуйте записи, а потім їх серіалізуйте, надавши їм порядкові номери. Отже, rownum> 1 - це дублікати записів, які можна видалити як такі.


Мені це подобається, оскільки він дозволяє легко додавати більше стовпців у внутрішній пункт вибору. Тож якщо ви хочете повернути інші стовпці з таблиці "Організації", вам не потрібно робити "групи за" в цих стовпцях.
Gwasshoppa


2
select a.orgName,b.duplicate, a.id
from organizations a
inner join (
    SELECT orgName, COUNT(*) AS duplicate
    FROM organizations
    GROUP BY orgName
    HAVING COUNT(*) > 1
) b on o.orgName = oc.orgName
group by a.orgName,a.id

1
select orgname, count(*) as dupes, id 
from organizations
where orgname in (
    select orgname
    from organizations
    group by orgname
    having (count(*) > 1)
)
group by orgname, id

1

У вас є кілька способів для Select duplicate rows.

для моїх рішень спочатку розглянемо, наприклад, цю таблицю

CREATE TABLE #Employee
(
ID          INT,
FIRST_NAME  NVARCHAR(100),
LAST_NAME   NVARCHAR(300)
)

INSERT INTO #Employee VALUES ( 1, 'Ardalan', 'Shahgholi' );
INSERT INTO #Employee VALUES ( 2, 'name1', 'lname1' );
INSERT INTO #Employee VALUES ( 3, 'name2', 'lname2' );
INSERT INTO #Employee VALUES ( 2, 'name1', 'lname1' );
INSERT INTO #Employee VALUES ( 3, 'name2', 'lname2' );
INSERT INTO #Employee VALUES ( 4, 'name3', 'lname3' );

Перше рішення:

SELECT DISTINCT *
FROM   #Employee;

WITH #DeleteEmployee AS (
                     SELECT ROW_NUMBER()
                            OVER(PARTITION BY ID, First_Name, Last_Name ORDER BY ID) AS
                            RNUM
                     FROM   #Employee
                 )

SELECT *
FROM   #DeleteEmployee
WHERE  RNUM > 1

SELECT DISTINCT *
FROM   #Employee

Безпечне рішення: Використовуйте identityполе

SELECT DISTINCT *
FROM   #Employee;

ALTER TABLE #Employee ADD UNIQ_ID INT IDENTITY(1, 1)

SELECT *
FROM   #Employee
WHERE  UNIQ_ID < (
    SELECT MAX(UNIQ_ID)
    FROM   #Employee a2
    WHERE  #Employee.ID = a2.ID
           AND #Employee.FIRST_NAME = a2.FIRST_NAME
           AND #Employee.LAST_NAME = a2.LAST_NAME
)

ALTER TABLE #Employee DROP COLUMN UNIQ_ID

SELECT DISTINCT *
FROM   #Employee

і в кінці всього рішення використовуйте цю команду

DROP TABLE #Employee

0

я думаю, я знаю, що тобі потрібно, щоб змішати відповіді, і я думаю, що я отримав рішення, яке він хотів:

select o.id,o.orgName, oc.dupeCount, oc.id,oc.orgName
from organizations o
inner join (
    SELECT MAX(id) as id, orgName, COUNT(*) AS dupeCount
    FROM organizations
    GROUP BY orgName
    HAVING COUNT(*) > 1
) oc on o.orgName = oc.orgName

макс. ідентифікатор надасть вам ідентифікатор дубліката та оригінал, про який він попросив:

id org name , dublicate count (missing out in this case) 
id doublicate org name , doub count (missing out again because does not help in this case)

тільки сумна річ, яку ви викладаєте в такому вигляді

id , name , dubid , name

сподіваюся, що це все ще допомагає


0

Припустимо, у нас є таблиця таблиці "Студент" з 2 стовпцями:

  • student_id int
  • student_name varchar

    Records:
    +------------+---------------------+
    | student_id | student_name        |
    +------------+---------------------+
    |        101 | usman               |
    |        101 | usman               |
    |        101 | usman               |
    |        102 | usmanyaqoob         |
    |        103 | muhammadusmanyaqoob |
    |        103 | muhammadusmanyaqoob |
    +------------+---------------------+

Тепер ми хочемо побачити повторювані записи. Використовуйте цей запит:

select student_name,student_id ,count(*) c from student group by student_id,student_name having c>1;

+---------------------+------------+---+
| student_name        | student_id | c |
+---------------------+------------+---+
| usman               |        101 | 3 |
| muhammadusmanyaqoob |        103 | 2 |
+---------------------+------------+---+

0

У мене є кращий варіант отримати дублікати записів у таблиці

SELECT x.studid, y.stdname, y.dupecount
FROM student AS x INNER JOIN
(SELECT a.stdname, COUNT(*) AS dupecount
FROM student AS a INNER JOIN
studmisc AS b ON a.studid = b.studid
WHERE (a.studid LIKE '2018%') AND (b.studstatus = 4)
GROUP BY a.stdname
HAVING (COUNT(*) > 1)) AS y ON x.stdname = y.stdname INNER JOIN
studmisc AS z ON x.studid = z.studid
WHERE (x.studid LIKE '2018%') AND (z.studstatus = 4)
ORDER BY x.stdname

Результат вищезазначеного запиту показує всі повторювані імена з унікальними ідентифікаторами учнів та кількістю повторюваних завдань

Клацніть тут, щоб побачити результат sql


0
 /*To get duplicate data in table */

 SELECT COUNT(EmpCode),EmpCode FROM tbl_Employees WHERE Status=1 
  GROUP BY EmpCode HAVING COUNT(EmpCode) > 1

0

Я використовую два методи для пошуку повторюваних рядків. 1-й метод є найвідомішим із використання групи за допомогою і наявності. Другий метод - це використання CTE - Загальна таблична виразність .

Як згадував @RedFilter, цей спосіб також є правильним. Багато разів я знаходжу метод CTE також для мене корисний.

WITH TempOrg (orgName,RepeatCount)
AS
(
SELECT orgName,ROW_NUMBER() OVER(PARTITION by orgName ORDER BY orgName) 
AS RepeatCount
FROM dbo.organizations
)
select t.*,e.id from organizations   e
inner join TempOrg t on t.orgName= e.orgName
where t.RepeatCount>1

У наведеному вище прикладі ми зібрали результат, знайшовши повторення за допомогою ROW_NUMBER та PARTITION BY. Тоді ми застосували там, де в пункті вибору лише рядків, які на повторному рахунку перевищують 1. Весь результат збирається таблицею CTE і об'єднується з таблицею Організації.

Джерело: CodoBee


-2

Спробуйте

SELECT orgName, id, count(*) as dupes
FROM organizations
GROUP BY orgName, id
HAVING count(*) > 1;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.