質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.65%

重複したレコードを1件だけ残して削除したい

解決済

回答 5

投稿

  • 評価
  • クリップ 3
  • VIEW 15K+

chibi_kuma

score 45

postgreSQL(ver9.3.5)のデータベースを、phpPgAdmin(ver5.1)で操作しています。

phpPgAdmin でテーブルを表示させた時、
操作欄(編集ボタン/削除ボタン)が付くテーブルと付かないテーブルとがあり、
原因を調べてみた所、操作欄が無いテーブルには「プライマリキー」が
設定されていない事が原因と分かりました。

phpPgAdmin

そこで早速、プライマリーキーを追加してみたところ、
レコードが重複しているというエラーが出て、
プライマリーキーを追加することが出来ませんでした。

SELECT文で確認してみると、
確かにレコードが重複していて、
しかも全フィールド内容が一致してしまっています。
あちゃー。

テーブル名 order_progress_table
--------------------------------------------------------
id     order_num     progress_info     processing_date
--------------------------------------------------------
19314    08071401    4    2008-07-14 09:25:15.423073
19314    08071401    4    2008-07-14 09:25:15.423073
19314    08071401    4    2008-07-14 09:25:15.423073
--------------------------------------------------------

1件だけレコードを残して削除したいのですが、
以下のSQL文だと、全て消えてしまいそうです。

DELETE FROM order_progress_table WHERE ID = 19314;

どのようにすれば、1件だけ残して削除することが出来ますでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

+10

既に解決済みのようですが、中間テーブルを用いない方法として以下のようなSQLをご紹介します。
⇒参考
IDをプライマリキーにしたい場合(IDが重複するデータを1つのみ残して削除する)

DELETE FROM order_progress_table  
 USING
   ( SELECT id, max(ctid) AS ctid FROM test GROUP BY id ) AS X
    WHERE X.id = order_progress_table.id AND X.ctid <> order_progress_table.ctid ;

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+7

PostgreSQL9.1の新機能の「WITH句とINSERT,UPDATE,DELETEを同時に」
http://lets.postgresql.jp/documents/technical/9.1/1#writable-cte
を見ながらPostgreSQL9.5で作ってみました :-)

with tmp as(delete from order_progress_table Returning *)
Insert Into order_progress_table select distinct * from tmp;

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+1

良いコマンドが思いつかないのでとりあえずのSQL

create temp table tmp_order_progress_table as select distinct * from order_progress_table;
truncate table order_progress_table;
insert into order_progress_table select * from tmp_order_progress_table;

3ステップも必要です。

念の為に実行前に
>pg_dump -U user -t order_progress_table db > order_progress_table.dmp
を行ってからです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/27 17:41

    A.Ichi さん、ありがとうございます!!
    すごいです!
    一回でやろうとすると難しいけれど、段階を踏めばシンプルに出来るんですね。
    なにやら小難しいことばかり考えていておりました。
    自分の知らないコマンドもあり、勉強になりました。

    DBにコマンドラインではアクセスが出来なかったので、pg_dumpはできませんでした。
    phpPgAdminでテーブルをエクスポーtトしてからやりました。
    そこまでケアしていただき、感謝です。

    ありがとうございました。またよろしくお願い致します。

    キャンセル

+1

PostgreSQLにはWITH句で、削除しながらを削除データを別テーブルに書き出せる例が掲載されていました。
削除後に、別テーブルのデータを一意化して 元のテーブル戻す(INSERT)すれば解決ですね。
よくかんがえたら、別にWITH句使わなくてもできますね。
削除予定分を別テーブルに取り出してから、削除すれば同じことですから、、、

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

MySQLなら LIMIT 区で1個ずつできます。
1個ずつなので個数が多い場合は、他の方法。
CREATE TABLE temp.chk (f1 VARCHAR(8), f2 VARCHAR(8));
INSERT INTO temp.chk values('0001','abc'),('0001','def');
DELETE FROM temp.chk WHERE f1='0001' LIMIT 1;
SELECT * FROM temp.chk;
件数が多い場合は、一旦外部ファイルに書き出す
SELECT DISTINCT * FROM temp.chk INTO OUTFILE '/temp/chk.txt'
FIELDS TERMINATED BY ','   OPTIONALLY ENCLOSED BY '"';
TRUNCATE TABLE temp.chk;
LOAD DATA LOCAL INFILE '/temp/chk.txt'
INTO TABLE temp.chk
CHARACTER SET utf8mb4 FIELDS ESCAPED BY '' TERMINATED BY ',' ENCLOSED BY '"' ;
PG_SQLにも対応する機能があっても良さそうですね。 
別テーブルに書き出す。
CREATE TABLE temp.dmp SELECT DISTINCT * FROM temp.chk;
DROP TABLE temp.chk;
ALTER TABLE temp.dmp RENAME chk;

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.65%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる