これらの行に主キーまたはその他の一意の識別子列がある場合に、SQLServerで重複する行を見つけるための7つのオプションを次に示します。
つまり、テーブルには、一意の識別子列を除いて、すべての列でまったく同じ値を共有する2つ以上の行が含まれています。
次のデータを含むテーブルがあるとします。
SELECT * FROM Dogs;
結果:
+---------+-------------+------------+ | DogId | FirstName | LastName | |---------+-------------+------------| | 1 | Bark | Smith | | 2 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +---------+-------------+------------+
最初の2行が重複していることがわかります(DogId
を除く) 列。すべての行で一意の値が含まれ、テーブルの主キー列として使用できます)。また、最後の3行が重複していることもわかります(DogId
を除く) 列)。
一意のID列により、重複する行がないことが保証されます。これは通常、RDBMSで非常に望ましい特性です。ただし、この場合、重複を見つける機能を妨げる可能性があります。定義上、一意のID列は、重複がないことを保証します。幸い、次の例に示すように、この問題は非常に簡単に解決できます。
おそらく、それを行う最も簡単で簡単な方法は、GROUP BY
を使用する単純なクエリを使用することです。 条項:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
結果:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Woof | Jones | 1 | | Ruff | Robinson | 1 | | Bark | Smith | 2 | +-------------+------------+---------+
クエリからプライマリキー/一意のID列を除外することで、除外することができました。
結果は、Wag Johnsonを含む3つの行と、BarkSmithを含む2つの行があることを示しています。これらは重複しています(またはWag Johnsonの場合は3回です)。
HAVING
を含めることで、重複しないものを結果から除外できます。 クエリの句:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
結果:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Bark | Smith | 2 | +-------------+------------+---------+
連結された列の重複をチェックすることもできます。たとえば、CONCAT()
を使用できます 2つの列を連結する関数:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
結果:
+---------------+---------+ | DogName | Count | |---------------+---------| | Bark Smith | 2 | | Ruff Robinson | 1 | | Wag Johnson | 3 | | Woof Jones | 1 | +---------------+---------+
ROW_NUMBER()
を使用できます PARTITION BY
で機能する 重複するたびに増分するが、一意の行があると再びリセットされる行番号を持つ新しい列を作成する句:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
結果:
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 1 | Bark | Smith | 1 | | 2 | Bark | Smith | 2 | | 4 | Ruff | Robinson | 1 | | 5 | Wag | Johnson | 1 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | | 3 | Woof | Jones | 1 | +---------+-------------+------------+--------------+
この方法の利点の1つは、結果をグループ化していないため、重複するすべての行とその一意の識別子列を表示できることです。
前の例を、より大きなクエリの一般的なテーブル式として使用することもできます。
WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs
)
SELECT * FROM cte WHERE Row_Number <> 1;
結果:
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 2 | Bark | Smith | 2 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +---------+-------------+------------+--------------+
このオプションは、非重複を出力から除外します。
また、各重複の1行だけを出力から除外します。これにより、最後のSELECT *
を回すための扉が開かれます。 DELETE
に 各複製を1つずつ保持しながら、テーブルの複製を解除します。
前の例と同じ出力を取得するためのより簡潔な方法は次のとおりです。
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
結果:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
この例では、独自の行番号を生成する必要はありません。
最後に、重複する行を返すためのもう少し複雑な手法を次に示します。
SELECT *
FROM Dogs d1, Dogs d2
WHERE d1.FirstName = d2.FirstName
AND d1.LastName = d2.LastName
AND d1.DogId <> d2.DogId
AND d1.DogId = (
SELECT MAX(DogId)
FROM Dogs d3
WHERE d3.FirstName = d1.FirstName
AND d3.LastName = d1.LastName
);
結果:
+---------+-------------+------------+---------+-------------+------------+ | DogId | FirstName | LastName | DogId | FirstName | LastName | |---------+-------------+------------+---------+-------------+------------| | 2 | Bark | Smith | 1 | Bark | Smith | | 7 | Wag | Johnson | 5 | Wag | Johnson | | 7 | Wag | Johnson | 6 | Wag | Johnson | +---------+-------------+------------+---------+-------------+------------+
結果でさえもっと複雑に見えますが、ねえ、それでも重複が表示されます!