2016-08-26 13 views
1

私は繰り返しコードを持つテーブルを持っていますが、テーブルをきれいにする必要があります。テーブルから繰返しIDを削除する - パフォーマンス改善

私のテーブルにはこれです:私はこれを持っている(ちょうど少なくとも一つを持っているために、残された行は関係ありません)

FriendlyFunctionCode  MemberFirmId  FunctionLevel3Desc 
1       Value1   Value2 
2       Value4   Value5 

:私はこのようなものが必要

FriendlyFunctionCode  MemberFirmId  FunctionLevel3Desc 
1       Value1   Value2 
1       Value2   Value3 
2       Value4   Value5 

クエリが、パフォーマンスはひどいです

SELECT MemberFirmId, FriendlyFunctionCode 
INTO #ToDeleteRepeated 
FROM [dbo].[FirmFunction] 
GROUP BY MemberFirmId, FriendlyFunctionCode 
HAVING COUNT(1) > 1 

DECLARE @Code VARCHAR(100), @Desc VARCHAR(250) 

WHILE ((SELECT COUNT(1) FROM #ToDeleteRepeated) > 0) 
BEGIN 
    SELECT TOP 1 @Code = FriendlyFunctionCode FROM #ToDeleteRepeated 
    WHILE ((SELECT COUNT(1) FROM [FirmFunction] WHERE FriendlyFunctionCode = @Code) > 0) 
    BEGIN 
     SELECT TOP 1 @Desc = FunctionLevel3Desc FROM [FirmFunction] WHERE FriendlyFunctionCode = @Code 
     DELETE FROM [FirmFunction] WHERE FriendlyFunctionCode = @Code AND FunctionLevel3Desc = @Desc 
    END 
END 

ご意見はありますか?

+0

単一のスキャンでより速く実行しますFriendlyFunctionCodeに関連した異なる値?あなたの質問はそうしないことを示唆しています。実際には、FunctionLevel3Descも繰り返されると、クエリによって複数のレコードが削除されることに注意してください。 – Matt

答えて

3
WITH CTE AS (SELECT MemberFirmId, FriendlyFunctionCode, 
       ROW_NUMBER() over (PARTITION by FriendlyFunctionCode  ORDER BY FriendlyFunctionCode  ) AS RN 
       FROM [dbo].[FirmFunction] 
     ) 
     DELETE CTE WHERE CTE.RN >1 
+2

私はちょうど 'FriendlyFunctionCode'によってパーティションが必要だと思います –

+1

@Evaldas Buinauskas私はあなたが正しい感謝だと思います – Cato

+0

恐ろしい答え、それも試してみて、魅力のように働いた。 – Rednaxel

1

このようなウィンドウ機能を使用できます。カーソルを使用する必要がなくなります(SQL Serverでうまく機能しません)。行番号で何をしているのかを見るために、内部の選択を自分で実行することができます。あなただけのFunctionCodeにMAXとグループを使用することができます

テストデータ

CREATE TABLE #TestData (FriendlyFunctionCode int, MemberFirmId nvarchar(10), FunctionLevel3Desc nvarchar(10)) 
INSERT INTO #TestData 
VALUES 
(1,'Value1','Value2') 
,(1,'Value2','Value3') 
,(2,'Value4','Value5') 

クエリ

SELECT 
a.FriendlyFunctionCode 
,a.MemberFirmId 
,a.FunctionLevel3Desc 
INTO #SavedData 
FROM 
(
    SELECT 
    FriendlyFunctionCode 
    ,MemberFirmId 
    ,FunctionLevel3Desc 
    ,ROW_NUMBER() OVER(PARTITION BY FriendlyFunctionCode ORDER BY FriendlyFunctionCode) RowNum 
    FROM #TestData 
) a 
WHERE a.RowNum = 1 

TRUNCATE TABLE #TestData 

INSERT INTO #TestData (FriendlyFunctionCode, MemberFirmId, FunctionLevel3Desc) 
SELECT 
FriendlyFunctionCode 
,MemberFirmId 
,FunctionLevel3Desc 
FROM #SavedData 

DROP TABLE #SavedData 

結果

FriendlyFunctionCode MemberFirmId FunctionLevel3Desc 
1      Value1   Value2    
2      Value4   Value5     
+1

正しい概念ですが、実際にはレコードを削除しません – Matt

+1

それは公正です。元のテーブルを切り捨て、保存したレコードを挿入するように私の答えを更新しました。削除よりも優れたパフォーマンスが必要です。 –

0

SELECT 
    FriendlyFunctionCode, 
    MAX(MemberFirmId) as MemberFirmId, 
    MAX(FunctionLevel3Desc) as FuncationLevel3Desc 
INTO #StagingTable 
FROM 
    FirmFunction 
GROUP BY 
    FriendlyFunctionCode 

そして、あなたのテーブルを切り捨て、それに戻って選択...またはちょうどすべて一緒にテーブルを作成し、そこに明確な(最大)レコードを挿入します。

TRUNCATE TABLE FirmFunction 

INSERT INTO FirmFunction (FriendlyFunctionCode,MemberFirmId,FunctionLevel3Desc) 
SELECT * FROM #StagingTable 

これは、あなたのオリジナルと同じスキーマを持つ例えば、テーブルFirmFunction2を作成し、それを名前を変更、その後、それに挿入するよりも小さい安全です....

SELECT TOP 1 INTO FirmFunction2 FROM FirmFunction WHERE 1=0 

INSERT INTO FirmFunction2 (FriendlyFunctionCode, MemberFirmId, FunctionLevel3Desc) 
SELECT 
     FriendlyFunctionCode, 
     MAX(MemberFirmId) as MemberFirmId, 
     MAX(FunctionLevel3Desc) as FuncationLevel3Desc 
    INTO #StagingTable 
    FROM 
     FirmFunction 
    GROUP BY 
     FriendlyFunctionCode 

次にあなたがチェックすることができますFirmFunction2の日付と満足している場合は、他のテーブルを削除した後に名前を変更してください。

+0

良いアプローチは、それと魅力のように動作します。ありがとうございました。 – Rednaxel

+1

@Rednaxel私は、CTEの素晴らしさを強調したいと思いますが、非常に注意して使用してください。初心者(初心者だと言っているわけではありません)は、一時テーブルを使用できない一時テーブルのように使用することがよくあります。あなたの状況で意図的にやっているように、CTEが元のデータソースに影響を及ぼすことを除いて、これには何も問題はありません。したがって、CTEを使用して実行して挿入、削除などを行うと、元に戻ることはありません。正しい構文であることを確認してください...正しく仕分けして注文してください。私が提供した方法は合理化されていませんが、間違いが起こりにくいです。 – scsimon

+0

あなたのコメントをありがとう、私はCTEに注意します。 – Rednaxel

2

(ROW_NUMBERとCTEを使用して削除)

;with cte as (
select *, row_number() over(partition by friendlyfunctioncode order by memberfirmid) rn 
from deletingtable) 
delete from cte where rn > 1 

これは、以下の実行プランと実行:

表/クラスタ化インデックススキャン - >ソート(NOインデックス場合) - >セグメント - >シーケンスプロジェクト - それはFriendlyFunctionCode上で適切なインデックスを持っている場合、>フィルタや削除、

は、それは彼らが持っているとき、最初のあなたは、あなたが維持されたレコードを気にしたり削除します

+0

テーブルに追加可能なインデックスはありますか? –

+0

繰り返し削除しませんでした。 – Rednaxel

+0

より多くの索引がある場合、それらの索引は削除のためにオーバーヘッドを持ちます –

関連する問題