4

重複の可能性:
重複するエントリを見つけてSQLで最も古いエントリを削除するにはどうすればよいですか?

更新ツールの欠陥が原因で、数千の重複があるデータベースがあります。重複しているアイテムのコレクションを特定することはできますが、最も古いエントリのみを削除する必要があります。必ずしも最小のIDである必要はありません。テストデータは次のようになります。正しい行には*があります。

重複するルールIDを持たない重複するタイトルの記事は、最後に作成された行を除いて削除する必要があります。(実際のID列はGUIDであるため、自動インクリメントを想定できません)

Id           Article id          Rule Id         Title          Opened Date
--           ----------          -------         -----          -----------
1*           111                 5               T1             2013-01-20
2            112                 5               T1             2013-07-01
3*           113                 6               T2             2013-07-01
4*           114                 7               T2             2013-07-02
5            115                 8               T3             2012-07-01
6            116                 8               T3             2013-01-20
7*           117                 8               T3             2013-01-21           

テーブルスキーマ:

CREATE TABLE [dbo].[test_ai](
    [id] [int] NOT NULL,
    [ArticleId] [varchar](50) NOT NULL,
    [ruleid] [varchar](50) NULL,
    [Title] [nvarchar](max) NULL,
    [AuditData_WhenCreated] [datetime] NULL,
PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)

テストデータ挿入

insert into test_ai (id, articleid, ruleid, title, auditdata_whencreated) values (1, 111, 5, 'test 1', '2013-01-20')
insert into test_ai (id, articleid, ruleid, title, auditdata_whencreated) values (2, 112, 5, 'test 1', '2012-07-01')
insert into test_ai (id, articleid, ruleid, title, auditdata_whencreated) values (3, 113, 6, 'test 2', '2012-07-01')
insert into test_ai (id, articleid, ruleid, title, auditdata_whencreated) values (4, 114, 7, 'test 2', '2012-07-02')
insert into test_ai (id, articleid, ruleid, title, auditdata_whencreated) values (5, 115, 8, 'test 3', '2012-07-01')
insert into test_ai (id, articleid, ruleid, title, auditdata_whencreated) values (6, 116, 8, 'test 3', '2013-01-20')
insert into test_ai (id, articleid, ruleid, title, auditdata_whencreated) values (7, 117, 8, 'test 3', '2013-01-21')

私の現在のクエリは次のようになります

select * from test_ai
where test_ai.id in

-- set 1 - all rows with duplicates
(select f.id 
from test_ai as F 
WHERE exists (select ruleid, title, count(id)   
FROM test_ai
    WHERE test_ai.title = F.title
        AND test_ai.ruleid = F.ruleid
    GROUP BY test_ai.title, test_ai.ruleid
    having count(test_ai.id) > 1))
    and test_ai.id not in

-- set 2 - includes one row from each set of duplicates
(select min(id)
from test_ai as F
WHERE EXISTS (select ruleid, title, count(id)
from test_ai
WHERE test_ai.title = F.title 
    AND test_ai.ruleid = F.ruleid
group by test_ai.title, test_ai.ruleid
HAVING count(test_ai.id) > 1)   
GROUP BY title, ruleid
)   

このSQLは、削除する必要のある行の一部(行2、6、7)を識別しますが、「オープン日」までに最も古い記事を選択します。(行2、5、6を削除する必要があります)これをステートメントに指定していないことに気付きましたが、この最後の部分を追加する方法に苦労しています。複数の重複があるときに重複を削除するために複数回実行する必要があるスクリプトが生成された場合、それは問題ではありません。

実際の問題はかなり複雑ですが、この1つのブロック部分を乗り越えることができれば、再び前進することができます。ご覧いただきありがとうございます!

4

1 に答える 1

4

SQL Server 2005+でセット(またはセット内の各グループ)から1つの行を削除するための一般的なモデルは次のとおりです。

;WITH cte AS 
(
  SELECT col, rn = ROW_NUMBER() OVER 
    (PARTITION BY something ORDER BY something)
  FROM dbo.base_table
  WHERE ...
)
DELETE x WHERE rn = 1;

あなたの場合、これは次のようになります。

;WITH cte AS 
(
  SELECT id, ruleid, Title, rn = ROW_NUMBER() OVER 
  (
     PARTITION BY ruleid, Title  
     ORDER BY auditdata_whencreated DESC
  )
  FROM dbo.test_ai
)
DELETE cte 
  OUTPUT deleted.id
  WHERE rn > 1;

結果:

id
----
2
6
5
于 2013-01-21T23:23:29.047 に答える