Bagaimana cara menyalin batasan unik di Oracle dengan SQLAlchemy?

Saya memiliki tabel (yang tidak dapat saya kendalikan) yang harus saya salin. Skema target bisa sama dengan skema aslinya, sehingga semua indeks dan batasan harus didefinisikan tanpa nama, secara implisit.

Saya menggunakan Python 3.4.3 dengan SQLAlchemy 1.0.8 dan cx_Oracle 5.2.

Tabelnya seperti ini:

CREATE TABLE "MY_TABLE" 
(   "ITEMID" NUMBER(*,0) NOT NULL ENABLE, 
    "LABEL" NVARCHAR2(80) NOT NULL ENABLE, 
    "FIRSTCHILDID" NUMBER(*,0) NOT NULL ENABLE, 
    "LASTCHILDID" NUMBER(*,0) NOT NULL ENABLE, 
    "DEFAULTPARENTID" NUMBER(*,0) NOT NULL ENABLE, 
    "PICTUREID" NUMBER(6,0) NOT NULL ENABLE, 
    "SECURITYID" NUMBER(*,0) NOT NULL ENABLE, 
    PRIMARY KEY ("ITEMID")
    UNIQUE ("LABEL"));

Kode yang saya gunakan ada di https://Gist.github.com/toyg/9fb541ff3dbc8c175329 tetapi intinya adalah ini (smeta dan dmeta adalah Metadata sumber dan target, terikat):

table = Table(table_name, smeta, autoload=True)
target_name = prefix + str(table.name)
target_table = table.tometadata(dmeta, name=target_name)
for constraint in target_table.constraints:
    constraint.name = None
target_table.metadata.create_all(dengine)

Gagal dengan kesalahan ini:

sqlalchemy.exc.DatabaseError: (cx_Oracle.DatabaseError) 
ORA-00955: name is already used by an existing object 
[SQL: b'CREATE UNIQUE INDEX sys_c009016 ON "TMP_MY_TABLE" (label)']

Ini karena SQLAlchemy mencoba membuat indeks Unik setelah membuat tabel, padahal sudah terlambat: CREATE INDEX memerlukan nama, jadi SA menggunakan nama yang sama dengan yang sudah ada, dan gagal.

Saya mencoba menyetel nama indeks ke Tidak Ada sebelum pembuatan, untuk memberikan petunjuk kepada SA, tetapi hal itu menghasilkan kesalahan karena ia mengharapkan string di sana setiap saat.

Apakah ada cara untuk memberitahu SA untuk segera menambahkan klausa UNIK ke tabel DDL?


person Giacomo Lacava    schedule 13.08.2015    source sumber
comment
Anda mencoba mengkloning data? Jika skemanya sama   -  person Dmitry.Samborskyi    schedule 13.08.2015
comment
Ya, saya harus menyalin seluruh tabel. Skema mungkin sama atau mungkin tidak sama; masalahnya jelas muncul pada saat itu, tapi tbh, tabrakan nama bisa terjadi bahkan dalam skema yang berbeda.   -  person Giacomo Lacava    schedule 13.08.2015
comment
apakah kamu mencoba sesuatu seperti constraint.name = prefix + constraint.name? Dalam hal ini Anda akan memiliki nama untuk batasan, dan batasan tersebut akan berbeda dari batasan yang ada.   -  person pavel_form    schedule 13.08.2015
comment
maaf, maksud saya menyetel nama indeks   -  person pavel_form    schedule 13.08.2015
comment
Terima kasih @pavel_form , saya belum memikirkan hal itu. Ini masih merupakan solusi, tetapi jika saya tidak dapat menemukan cara yang lebih baik, saya akan melakukannya.   -  person Giacomo Lacava    schedule 13.08.2015


Jawaban (1)


"UNIQUE INDEX" berarti konstruk Index digunakan. DDL-nya tidak dipancarkan dalam CREATE TABLE. Sepertinya Anda sedang mencari konstruksi UniqueConstraint. Tampaknya dalam kasus ini, Oracle mengembalikan informasi yang tercermin tentang apa yang pertama kali Anda buat sebagai objek UniqueConstraint sebagai objek Index dengan unik=True (konstruksi ini "berbeda", tetapi pada banyak backend keduanya sama dan/atau dicampur dan dicocokkan dan kadang-kadang bahkan dicerminkan, itu benar-benar membingungkan).

pada akhirnya jika Anda ingin kata kunci UNIK sebagai batasan inline, Anda perlu menggunakan objek UniqueConstraint, dan Anda harus menghapus Index ini dari tabel - Anda mungkin bisa lolos dengan table.indexes.remove(index). Objek Index tidak akan berada di table.constraints. Anda mungkin ingin melakukan "penyalinan" tabel dengan cara yang lebih terprogram daripada menggunakan tometadata(). Mungkin pertimbangkan untuk menggunakan antarmuka inspeksi secara langsung dan buat saja Table yang Anda inginkan dari itu.

person zzzeek    schedule 14.08.2015