OS MasterMapデータを含むかなり大きなテーブル(約1億1,400万行)があります。これは、新しいテーブルに新しく読み込まれたデータです。主キーを設定しようとすると、次のエラーが発生します。
ERROR: could not create unique index "tbl_os_mmap_topoarea_pkey"
DETAIL: Key (toid)=(1000000004081308) is duplicated.
どういうわけか、私は正確に複製された行で終わりました。これらの2つの行のすべてのフィールドは同じです。 1つの行を削除したいが、もう1つの行は保持したい。 2つを区別する方法がないので、これをどのように行うことができますか?
これをできるだけ迅速かつ簡単に行いたいと思います。このサイズのデータセットでは時間がかかりすぎるため、一時テーブルなどの作成は実際にはオプションではありません。新しい一意のID列を作成する方が速いと思いますが、おそらく多少時間がかかります。
少し調べたところ、postgresのすべてのレコードに非表示の一意のIDであるctidがあることがわかりました。これを使用して重複行の1つを削除できますか?
これはうまくいくと思います:
with d as
( select ctid, row_number() over (partition by t.*) as rn
from tablename as t
)
delete from tablename as t
using d
where d.rn > 1
and d.ctid = t.ctid ;
そして別のバリエーション。どちらがより効率的かわかりません:
delete from tablename as t
where exists
( select *
from tablename as d
where d.ctid > t.ctid
and d.* is not distinct from t.*
) ;
しかし、ドキュメントが「ctid
」と言っていることに注意してください:
ctid
テーブル内の行バージョンの物理的な場所。
ctid
を使用すると、行のバージョンをすばやく見つけることができますが、VACUUM FULL
によって行が更新または移動されると、行のctid
が変更されます。したがって、ctid
は長期的な行識別子としては役に立ちません。論理行を識別するには、OID
、またはそれ以上のユーザー定義のシリアル番号を使用する必要があります。
したがって、テーブルがWITH OIDS
で作成された場合は、代わりにそれを使用してください。