これらの行に主キーまたはその他の一意の識別子列があり、それを無視したい場合に、OracleDatabaseで重複行を返すための11のオプションを次に示します。
例では、次のデータを使用します。
SELECT * FROM Dogs; 結果:
| DOGID | FIRSTNAME | 姓 |
|---|---|---|
| 1 | バーク | スミス |
| 2 | バーク | スミス |
| 3 | Woof | ジョーンズ |
| 4 | ラフ | ロビンソン |
| 5 | ワグ | ジョンソン |
| 6 | ワグ | ジョンソン |
| 7 | ワグ | ジョンソン |
最初の2行は重複しており、最後の3行は重複しています。重複する行は、主キー/一意のID列を除いて、すべての列でまったく同じ値を共有します。
主キーの列は、重複する行がないことを保証します。これは、主キーがデータの整合性を強化するのに役立つため、RDBMSでは適切な方法です。ただし、主キーに一意の値が含まれているという事実は、重複を検索するときにその列を無視する必要があることを意味します。
上記の表では、主キー列は増分番号であり、その値は意味を持たず、重要ではありません。したがって、重複を検索するときは、その列のデータを無視できます。
重複を返すための最初のオプションは次のとおりです。
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
ORDER BY Count DESC; 結果:
| FIRSTNAME | 姓 | COUNT |
|---|---|---|
| ワグ | ジョンソン | 3 |
| バーク | スミス | 2 |
| ラフ | ロビンソン | 1 |
| Woof | ジョーンズ | 1 |
ここでは、 GROUP BYを使用してクエリを作成しました 出力が関連する列によってグループ化されるように句。 COUNT()も使用しました 同一の行の数を返す関数。そして、重複が最初に表示されるように、カウントの降順で並べ替えました。
結果は、Wag Johnsonを含む3つの行と、BarkSmithを含む2つの行があることを示しています。これらは重複しています(またはWag Johnsonの場合は3回)。他の2つの行には重複がありません。
HAVINGを追加できます 出力から非重複を除外するための前の例の句:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1
ORDER BY Count DESC; 結果:
| FIRSTNAME | 姓 | COUNT |
|---|---|---|
| ワグ | ジョンソン | 3 |
| バーク | スミス | 2 |
連結された列の重複をチェックすることもできます。この場合、 DISTINCTを使用します キーワードを使用して個別の値を取得し、 COUNT()を使用します カウントを返す関数:
SELECT
DISTINCT FirstName || ' ' || LastName AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName || ' ' || LastName
ORDER BY Count DESC; 結果:
| DOGNAME | COUNT |
|---|---|
| ワグジョンソン | 3 |
| バークスミス | 2 |
| ラフロビンソン | 1 |
| Woof Jones | 1 |
Oracleの各行にはrowidがあります 行のアドレスを返す疑似列。 rowid はテーブル内の行の一意の識別子であり、通常、その値はデータベース内の行を一意に識別します(ただし、同じクラスターに一緒に格納されている異なるテーブル内の行は同じ rowid を持つ可能性があることに注意してください)。コード> 。
とにかく、 rowidを使用するクエリを作成できます 必要に応じて:
SELECT * FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.rowid > d2.rowid
); 結果:
| DOGID | FIRSTNAME | 姓 |
|---|---|---|
| 2 | バーク | スミス |
| 6 | ワグ | ジョンソン |
| 7 | ワグ | ジョンソン |
SELECT *を置き換えることができます DELETEを使用 テーブルに対して重複排除操作を実行します。
DogIdを使用できた可能性があることに注意してください rowid の代わりにcolumn(主キー) 必要に応じて。そうは言っても、 rowid 何らかの理由で主キー列を使用できない場合、またはテーブルに主キーがない場合に役立ちます。
rowidを使用する別のクエリを次に示します。 :
SELECT * FROM Dogs
WHERE rowid > (
SELECT MIN(rowid) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
); 結果:
| DOGID | FIRSTNAME | 姓 |
|---|---|---|
| 2 | バーク | スミス |
| 6 | ワグ | ジョンソン |
| 7 | ワグ | ジョンソン |
前の例と同様に、 SELECT *を置き換えることができます DELETEを使用 重複する行を削除します。
2つのrowid 上記のオプションは、クエリで主キーを完全に無視する必要がある場合(または、主キー列がまったくない場合)に最適です。ただし、前述のように、 rowidを置き換えるオプションはまだあります。 主キー列を使用–この場合は DogId 列:
SELECT * FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.DogId > d2.DogId
); 結果:
| DOGID | FIRSTNAME | 姓 |
|---|---|---|
| 2 | バーク | スミス |
| 6 | ワグ | ジョンソン |
| 7 | ワグ | ジョンソン |
そして、これが rowidを使用したもう1つのクエリです。 DogIdに置き換えられました 列:
SELECT * FROM Dogs
WHERE DogId > (
SELECT MIN(DogId) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
); 結果:
| DOGID | FIRSTNAME | 姓 |
|---|---|---|
| 2 | バーク | スミス |
| 6 | ワグ | ジョンソン |
| 7 | ワグ | ジョンソン |
重複を見つける別の方法は、 ROW_NUMBER()を使用することです。 ウィンドウ関数:
SELECT
DogId,
FirstName,
LastName,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS row_num
FROM Dogs; 結果:
| DOGID | FIRSTNAME | 姓 | ROW_NUM |
|---|---|---|---|
| 1 | バーク | スミス | 1 |
| 2 | バーク | スミス | 2 |
| 4 | ラフ | ロビンソン | 1 |
| 7 | ワグ | ジョンソン | 1 |
| 5 | ワグ | ジョンソン | 2 |
| 6 | ワグ | ジョンソン | 3 |
| 3 | Woof | ジョーンズ | 1 |
PARTITIONの使用 句を指定すると、新しい列が追加され、重複するたびに行番号が増加しますが、一意の行があると再びリセットされます。
この場合、結果はグループ化されません。つまり、一意の識別子列を含む、重複する各行を確認できます。
前の例を、より大きなクエリの一般的なテーブル式として使用することもできます。
WITH cte AS
(
SELECT
DogId,
FirstName,
LastName,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS row_num
FROM Dogs
)
SELECT * FROM cte WHERE row_num <> 1; 結果:
| DOGID | FIRSTNAME | 姓 | ROW_NUM |
|---|---|---|---|
| 2 | バーク | スミス | 2 |
| 5 | ワグ | ジョンソン | 2 |
| 6 | ワグ | ジョンソン | 3 |
このクエリは、非重複を出力から除外し、各重複の1行を出力から除外します。
前の例と同じ出力を取得する別の方法は次のとおりです。
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
MINUS SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
); 結果:
| DOGID | FIRSTNAME | 姓 |
|---|---|---|
| 2 | バーク | スミス |
| 6 | ワグ | ジョンソン |
| 7 | ワグ | ジョンソン |
この例では、Oracleの MINUSを使用しています 演算子。最初のクエリで返された一意の行のみを返し、2番目のクエリでは返しません。
MINUS 演算子はEXCEPTに似ています SQL Server、MariaDB、PostgreSQL、SQLiteなどの他のDBMSの演算子。
テーブルから重複を選択するためのさらに別のオプションは次のとおりです。
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 | 姓 | DOGID | FIRSTNAME | 姓 |
|---|---|---|---|---|---|
| 2 | バーク | スミス | 1 | バーク | スミス |
| 7 | ワグ | ジョンソン | 5 | ワグ | ジョンソン |
| 7 | ワグ | ジョンソン | 6 | ワグ | ジョンソン |