SQL Serverでの重複行の検索


231

組織のSQL Serverデータベースがあり、重複する行が多数あります。selectステートメントを実行して、これらすべてと重複の量を取得するだけでなく、各組織に関連付けられているIDも返します。

次のようなステートメント:

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

のようなものを返します

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

しかし、それらのIDも取得したいと思います。これを行う方法はありますか?たぶん

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

その理由は、これらの組織にリンクするユーザーの個別のテーブルも存在するためです。それらを統合したいと考えています(したがって、ユーザーを複製組織の代わりに同じ組織にリンクするように、複製を削除します)。しかし、手動でパーツを作成して、何も台無しにしないようにしたいのですが、ユーザーのリストを確認できるように、すべての複製組織のIDを返すステートメントが必要です。

回答:


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
たとえば、レコード数が1000万以上の場合、このクエリには制限がありますか?
スチーム

3
@Steam正解です。この回答は、何百万ものレコードがある大規模なデータベースでは効率的ではありません。Aykutから送信されたGroupBy / Havingの回答を優先します。これは、データベースによってより最適化できます。1つの例外:物事を簡略化するために、Count(*)ではなくCount(0)を使用することをお勧めします。
マイククリスチャン

1
@マイク-なぜCount(0)対Count(*)なのか?
KornMuffin

2
@KornMuffin振り返ってみると、Count()に関する私のコメントは無効です。Count()でnull以外の評価を使用することは、外部結合によって返されるnull以外の結果をカウントする場合にのみ役立ちます。それ以外の場合は、Count(*)を使用します。素晴らしい説明がここにあります
マイククリスチャン

セクションのisnull()null許容列に使用on
Arif Ulusoy

92

次のクエリを実行して、重複を見つけてmax(id)それらの行を削除できます。

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

ただし、このクエリを数回実行する必要があります。


正確にMAX( COUNT(*) ) - 1何度も実行する必要がありますが、それでも実行可能かもしれません。
DerMike

1
こんにちは2のように最大IDの代わりにすべてのIDを取得する方法はありますか?@DerMike
Arijit 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

削除できるレコードのみを返す場合は(それぞれ1つずつ)、次のように使用できます。

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

最初のステートメントは機能しますが、2番目のステートメントは機能していないようです。
xtine

SQL Serverはrow_number()を認識できないようです。
xtine

ああ... SQL Serverの古いバージョンはありますか?私は、それがSQL Server 2005で導入されたと考えている
ポール

3
もう一度感謝します。これを行う必要があるたびに、私はここに来て、あなたを愛します
workabyte 14年

9

正しいとマークされた解決策は私にとってはうまくいきませんでしたが、私はこの答えが素晴らしく機能しているのを見つけました:MySqlの重複行のリストを取得する

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

結果セットには大量の重複が含まれるため、それらにも対処する必要があります。
Renan 2016年

1
idが数値の場合、チェックするn1.id > n2.idと各ペアが2回表示されるのを防ぎます。
16年

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

すべてのIDをコンマ分割または異なる列で取得する方法
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 

これはここで最速のソリューションであり、1,000万行を超えるデータをSELECTする場合です。ありがとう
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のレコードは、テーブル内の重複レコードになります。'Partition by'は、まずレコードごとにグループ化し、次にシリアル番号を指定してシリアル化します。そのため、rownum> 1は重複レコードとして削除される可能性があります。


これは、内部のselect句に簡単に列を追加できるため、これが好きです。したがって、「Organizations」テーブルから他の列を返したい場合、それらの列で「group by」を実行する必要はありません。
グワショッパ2015


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

Secoundソリューション: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を持っていると、デュブリケートのIDと、彼が要求したオリジナルのIDが得られます。

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'があるとします。

  • 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

上記のクエリの結果は、一意の学生IDと重複する発生回数を含むすべての重複する名前を示しています

SQLの結果を表示するには、ここをクリックしてください



0

重複する行を見つけるには、2つの方法を使用します。1つ目の方法は、グループバイアンドホールディングを利用する最も有名な方法です。2番目の方法は、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を使用して繰り返し発生を見つけることによって結果を収集しました。次に、where句を適用して、繰り返しカウントが1を超える行のみを選択しました。すべての結果はCTEテーブルで収集され、Organizationsテーブルと結合されます。

出典:CodoBee


-2

試す

SELECT orgName, id, count(*) as dupes
FROM organizations
GROUP BY orgName, id
HAVING count(*) > 1;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.