Postgres'te bir tabloyu (dizinler dahil) kopyalayın


85

Postgres masam var. Ondan bazı verileri silmem gerekiyor. Geçici bir tablo oluşturacak, verileri kopyalayacak, dizinleri yeniden oluşturacak ve ihtiyacım olan satırları silecektim. Orijinal tablodaki verileri silemiyorum çünkü bu orijinal tablo veri kaynağıdır. Bir durumda X'in silinmesine bağlı bazı sonuçlar almam gerekiyor, başka bir durumda Y'yi silmem gerekecek. Bu nedenle, tüm orijinal verilerin her zaman ortalıkta ve kullanılabilir olmasına ihtiyacım var.

Ancak tabloyu yeniden oluşturmak ve tekrar kopyalamak ve dizinleri yeniden oluşturmak biraz aptalca görünüyor. Postgres'te "Yapı, veri ve dizinler de dahil olmak üzere bu tablonun tamamen ayrı bir kopyasını istiyorum" diyecek bir şey var mı?

Maalesef PostgreSQL "CREATE TABLE .. LIKE X INCLUDING INDEXES" içermiyor

Yanıtlar:


108

Yeni PostgreSQL (dokümanlara göre 8.3'ten beri) "DAHİL DİZİNLERİ" kullanabilir:

# select version();
                                             version
-------------------------------------------------------------------------------------------------
 PostgreSQL 8.3.7 on x86_64-pc-linux-gnu, compiled by GCC cc (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu3)
(1 row)

Gördüğünüz gibi 8.3'te test ediyorum.

Şimdi tablo oluşturalım:

# create table x1 (id serial primary key, x text unique);
NOTICE:  CREATE TABLE will create implicit sequence "x1_id_seq" for serial column "x1.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "x1_pkey" for table "x1"
NOTICE:  CREATE TABLE / UNIQUE will create implicit index "x1_x_key" for table "x1"
CREATE TABLE

Ve nasıl göründüğüne bakın:

# \d x1
                         Table "public.x1"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x1_pkey" PRIMARY KEY, btree (id)
    "x1_x_key" UNIQUE, btree (x)

Şimdi yapıyı kopyalayabiliriz:

# create table x2 ( like x1 INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES );
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "x2_pkey" for table "x2"
NOTICE:  CREATE TABLE / UNIQUE will create implicit index "x2_x_key" for table "x2"
CREATE TABLE

Ve yapıyı kontrol edin:

# \d x2
                         Table "public.x2"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x2_pkey" PRIMARY KEY, btree (id)
    "x2_x_key" UNIQUE, btree (x)

PostgreSQL ön-8.3 kullanıyorsanız, 1 tablo belirtmek, dökümde tablo adını değiştirmek ve tekrar yüklemek için pg_dump'ı "-t" seçeneğiyle birlikte kullanabilirsiniz:

=> pg_dump -t x2 | sed 's/x2/x3/g' | psql
SET
SET
SET
SET
SET
SET
SET
SET
CREATE TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE

Ve şimdi tablo:

# \d x3
                         Table "public.x3"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x3_pkey" PRIMARY KEY, btree (id)
    "x3_x_key" UNIQUE, btree (x)

14
Bu şekilde, birincil anahtar dizisi (x1_id_seq) iki tablo arasında paylaşılacaktır!
Jauzsika

2
Ops, pg9.X ile, birincil anahtar dizisi "KISITLAMALARI DAHİL ETMEK" ("DİZİNLER DAHİL" değil) kullanılırken paylaşılacaktır.
Peter Krauss

44
[CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name
    [ (column_name [, ...] ) ]
    [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
    [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
    [ TABLESPACE tablespace ]
    AS query][1]  

İşte bir örnek

CREATE TABLE films_recent AS
  SELECT * FROM films WHERE date_prod >= '2002-01-01';

İlkinden yeni bir tablo oluşturmanın diğer yolu,

    CREATE TABLE films_recent (LIKE films INCLUDING INDEXES);  

    INSERT INTO films_recent
         SELECT *
           FROM books
          WHERE date_prod >= '2002-01-01';  

İkinci yöntem kullanılırsa , Postgresql'in tablo alanı sorunlarını düzeltmek için bir yaması olduğunu unutmayın.


Postgres'te "DAHİL OLAN ENDEKSLER" yoktur.
Rory

2
Hangi sürümü kullanıyorsunuz? En son
belgeyi

6
pg9.X ile, "KISITLAMALAR DAHİL" kullanıldığında ("DİZİNLER DAHİL" değil) birincil tuş dizisi iki tablo (!) arasında paylaşılacaktır.
Peter Krauss

Çalışmak için CREATE TABLE my_table (LIKE...)bunun yerine olması gerekebilir gibi görünüyor CREATE TABLE my_table LIKE.... Cevap düzenlendi.
Jason Swett

@PeterKrauss, paylaşılan birincil anahtar dizisi olayını çözdün mü? Bir grup veriyi yeni bir tabloya KOPYALAMAYA çalışıyorum. Eski tabloyu bırakıp yenisini yeniden adlandıramıyorum çünkü yenisindeki pk eskisini gösteriyor.
yellottyellott

5

Web'de birçok cevap var, bunlardan biri burada bulunabilir .

Böyle bir şey yaptım:

create table NEW ( like ORIGINAL including all);
insert into NEW select * from ORIGINAL

Bu, şemayı ve dizinler dahil verileri kopyalayacak, ancak tetikleyicileri ve kısıtlamaları içermeyecektir. Dizinlerin orijinal tabloyla paylaşıldığını, bu nedenle tablolardan herhangi birine yeni satır eklerken sayacın artacağını unutmayın.


4

Postgres masam var. Ondan bazı verileri silmem gerekiyor.

Sanırım ...

delete from yourtable
where <condition(s)>

... nedense işe yaramayacak. (Bu sebebi paylaşmak ister misiniz?)

Geçici bir tablo oluşturacak, verileri kopyalayacak, dizinleri yeniden oluşturacak ve ihtiyacım olan satırları silecektim.

Pg_dump ve pg_restore'a bakın. Pg_dump'ı bazı akıllı seçeneklerle kullanmak ve belki de çıktıyı pg_restoring'den önce düzenlemek işe yarayabilir.


Veriler üzerinde "what if" tipi analiz yaptığınız için, görünümleri kullanmanın daha iyi olup olmadığını merak ediyorum.

Hariç tutmak istediğiniz şeyin olumsuzlamasına dayalı olarak test etmek istediğiniz her senaryo için bir görünüm tanımlayabilirsiniz. Yani, dahil etmek istediğiniz şeye dayalı bir görünüm tanımlayın. Örneğin, veriler üzerinde X = Y olan satırları "sildiğiniz" bir "pencere" istiyorsanız, (X! = Y) satırları olarak bir görünüm oluşturursunuz.

Görünümler, tanımlayıcı sorguları olarak veritabanında (Sistem Kataloğu'nda) saklanır. Görünümü her sorguladığınızda, veritabanı sunucusu onu tanımlayan temel sorguyu arar ve bunu yürütür (kullandığınız diğer koşullarla VE ile birlikte). Bu yaklaşımın birçok faydası vardır:

  1. Verilerinizin herhangi bir bölümünü asla çoğaltmazsınız.
  2. Her bir görünümü / senaryoyu sorguladığınızda, temel tablo için halihazırda kullanımda olan dizinler (orijinal, "gerçek" tablonuz) kullanılacaktır (sorgu iyileştirici tarafından uygun görüldüğü gibi). Yeniden tanımlamaya veya kopyalamaya gerek yoktur.
  3. Görünüm, temel tablodaki "gerçek" veriler üzerinde bir "pencere" (şekil görüntüsü DEĞİL) olduğundan, temel tablonuza ekleyebilir / güncelleyebilir / silebilir ve herhangi bir şeyi yeniden oluşturmanıza gerek kalmadan görünüm senaryolarını yeniden sorgulayabilirsiniz. veriler zamanla değişir.

Elbette bir değiş tokuş var. Bir görünüm sanal bir tablo olduğundan ve "gerçek" (temel) bir tablo olmadığından, aslında her eriştiğinizde (belki karmaşık) bir sorgu yürütüyorsunuz. Bu işleri biraz yavaşlatabilir. Ama olmayabilir. Birçok konuya (verilerin boyutu ve niteliği, Sistem Kataloğundaki istatistiklerin kalitesi, donanımın hızı, kullanım yükü ve çok daha fazlası) bağlıdır. Deneyene kadar bilemeyeceksin. Eğer (ve ancak) gerçekten performansın kabul edilemez derecede yavaş olduğunu fark ederseniz, diğer seçeneklere bakabilirsiniz. (Materyalleştirilmiş görünümler, tabloların kopyaları ... zamanla yer değiştiren her şey.)


Neden orijinal tablodan silemediğimi açıklamak için soruyu güncelledim
Rory

1

İstediğiniz verileri almak için bir seçim kullanarak yeni bir tablo oluşturun. Sonra eski tabloyu yenisiyle değiştirin.

create table mynewone as select * from myoldone where ...
mess (re-create) with indexes after the table swap.

0

Basit bir yol, hepsini içerir:

CREATE TABLE new_table (LIKE original_table INCLUDING ALL);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.