2016-09-19 30 views
0

私はSQL Server 2014を使用しており、Microsoftが提供するAdventureWorks2012サンプルデータベースを利用しています。サブクエリを使用して重複する行を削除

私は(オプション#2)の下にサブクエリを使用して重複行を削除しようとしている:

/*オプション#2:SUBQUERY */

--SELECT * FROM 
DELETE SQLPractice.[dbo].[CURRENCY] 
WHERE EXISTS (SELECT * 
       FROM 
        (SELECT 
         NAME, 
         ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY NAME) AS Flag 
        FROM 
         SQLPractice.[dbo].[CURRENCY]) AS T 
       WHERE Flag > 1) 
GO 

しかし、それはすべての行を削除しますテーブルから。

ただし、他のオプション(CTE)では重複する行だけが削除されます。

/*** Option #3: CTE ***/ 
;WITH RepFlag AS 
(
    SELECT 
     NAME, 
     ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY NAME) AS Flag 
    FROM 
     SQLPractice.[dbo].[CURRENCY] 
) 
--SELECT * FROM RepFlag 
DELETE RepFlag 
WHERE Flag > 1 

SELECT * 
FROM SQLPractice.[dbo].[CURRENCY] 

独自のテストテーブルを作成するには、以下のコードを使用してください。

/*** REMOVING DUPLICATE ROWS OPTION ***/ 
-- Creating a table 
SELECT TOP 0 * 
INTO [dbo].[CURRENCY] 
FROM AdventureWorks2012.Sales.Currency 
WHERE NAME LIKE '%A'; 

-- inserting duplicate rows 
INSERT [dbo].[CURRENCY] 
SELECT * FROM AdventureWorks2012.Sales.Currency 
WHERE NAME LIKE '%A'; 

/***** SELECTING COUNT OF DUPLICATED ROWS *****/ 

/*** Option #1: "GROUP BY" with "HAVING" ***/ 
SELECT 
    NAME, COUNT(*) AS Qty 
FROM 
    SQLPractice.[dbo].[CURRENCY] 
GROUP BY 
    NAME 
HAVING 
    COUNT(*) >1 
GO 

答えて

1

オプション#2 EXISTS内のサブクエリは、常にテーブルのすべての行の行を返しますので、すべての行を削除します。 EXISTS内のサブクエリと親クエリの間には何らかの関係がある必要があります。サブクエリは、テーブルの各行に応じて異なる結果を生成する必要があります。一つのオプションの表は、アイデンティティCOLを持っている場合、サブクエリを使用して行を複製するために削除するには、次のとおりです。

DELETE from SQLPractice.[dbo].[CURRENCY] 
where identityCol not in (select min(identityCol) FROM SQLPractice.[dbo].[CURRENCY] GROUP BY NAME) 
+0

はい、ありがとうございます。私はそれについて考えました。テーブル定義を変更せずにバイパスする方法を知りたかっただけです。 – enigma6205

+0

あなたはcte –

+0

を使用できます。私はそれを使用しました。上のコードに示すように。さまざまなオプションを探求したかっただけです。 – enigma6205

0

Withステートメント、それはすべての重複レコードを収集して、削除操作を実行するため、行を複製するだけ削除します。

削除したいレコードの条件れている場所を指定していない、あなたのサブクエリで、それは以下のように書かれるべきであるが:可能な方法の

DELETE SQLPractice.[dbo].[CURRENCY] 
WHERE EXISTS 
(
    SELECT * FROM 
    (
     SELECT 
     NAME, 
     ID, 
     ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY NAME) AS Flag 
     FROM SQLPractice.[dbo].[CURRENCY] 
    ) AS T 
    WHERE Flag > 1 AND T.ID=[CURRENCY].ID 
) 
+0

これは、複数回出現している通貨の行もすべて削除しますか? –

+0

重複した商品は削除されますので、各通貨ごとに1つのレコードがあります –

+0

'US Dollar'が2回来ると、内部クエリはこれらの行の両方の行を返します。だから両方とも削除されます –

1

ワン:

DELETE tt 
FROM [your table] tt 
    INNER JOIN 

    (SELECT NAME, MIN(PK) AS MIN_KEY) 
    FROM [your table] 
    GROUP BY Name 
    HAVING COUNT(*) > 1) dup ON dup.name = tt.name and tt.PK <> dup.MIN_KEY 
+0

あなたの解決のためのアントンありがとうございますが、私のテーブルは主キーがないので動作しません。基本的には、Aksheyのソリューションと同様の提案をしています。 – enigma6205

+1

PKをお持ちでない場合は、カーソルまたは "WHILE loop + temp table"を使用することができます。したがって、重複した名前ごとに、 "DELETE TOP(xxx)..."を実行します。ここでxxxは "[現在の名前の重複数] - 1"です。 SET ROWCOUNTは、DELETE TOP – Anton

+1

の代わりに使用することもできます。または、重複する行のみをテンポラリ・テーブルにコピーし、すべての重複を削除して、テンポラリ・テーブルからデータを再挿入することもできます。 – Anton

0

あなたはこのクエリでこれを試すことができます。重複するレコードは削除されます。私はこの重複した値を削除します。

+0

ありがとうございますが、これによりすべての行が削除されます。だから、これはうまくいかないでしょう。 – enigma6205

1

サンプルケースでは、Row_Number()は問題の解決に役立ちません。 CurrencyCodeであるプライマリキー(候補フィールド)でも重複する行が同じであるため

同じ行をターゲットテーブルに挿入するだけで、ModifiedDateフィールドも同じになります。サンプルケースでは

、あなたは、あなたがテストし、DELETEコマンドの下のチュートリアルから例えば表に

delete [dbo].[CURRENCY] 
from [dbo].[CURRENCY] 
inner join (
    select ROW_NUMBER() over (partition by CurrencyCode order by ModifiedDate) rn, CurrencyCode, ModifiedDate from [dbo].[CURRENCY] 
) dublicates 
    on dublicates.CurrencyCode = [dbo].[CURRENCY].CurrencyCode and 
     dublicates.ModifiedDate = [dbo].[CURRENCY].ModifiedDate 
where dublicates.rn > 1 

をすべての行を削除することを見ることができますdelete duplicate rows where no primary key exists

に記載された解決策を適用することができますカーソルの方法は、使用して重複した名前を削除したい場合は、

DECLARE @Count int 
DECLARE @CurrencyCode varchar(10) 
DECLARE @ModifiedDate datetime 

DECLARE dublicate_cursor CURSOR FAST_FORWARD FOR 
SELECT CurrencyCode, ModifiedDate, Count(*) - 1 
FROM CURRENCY 
GROUP BY CurrencyCode, ModifiedDate 
HAVING Count(*) > 1 

OPEN dublicate_cursor 

FETCH NEXT FROM dublicate_cursor INTO @CurrencyCode, @ModifiedDate, @Count 

WHILE @@FETCH_STATUS = 0 
BEGIN 

SET ROWCOUNT @Count 
DELETE FROM CURRENCY WHERE CurrencyCode = @CurrencyCode AND ModifiedDate = @ModifiedDate 
SET ROWCOUNT 0 

FETCH NEXT FROM dublicate_cursor INTO @CurrencyCode, @ModifiedDate, @Count 
END 

CLOSE dublicate_cursor 
DEALLOCATE dublicate_cursor 
1

次使用することができます 示唆されましたsubquery、次の方法を使用します。

DELETE t 
FROM (SELECT NAME,ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY NAME) AS Flag 
       FROM SQLPractice.[dbo].[CURRENCY] 
      ) t 
WHERE t.Flag > 1 
GO 

また、これはc ommon table expression (CTE)を使用して達成することもできます。

;WITH cte_1 
AS (SELECT NAME,ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY NAME) AS Flag 
       FROM SQLPractice.[dbo].[CURRENCY] 
      ) 
DELETE FROM cte_1 
WHERE Flag > 1 
関連する問題