ฉันจะคัดลอกข้อ จำกัด ที่ไม่ซ้ำใน Oracle ด้วย SQLAlchemy ได้อย่างไร

ฉันมีตาราง (ซึ่งฉันไม่สามารถควบคุมได้) ที่ฉันต้องคัดลอก สคีมาเป้าหมายสามารถเหมือนกับสคีมาดั้งเดิมได้ ดังนั้นดัชนีและข้อจำกัดทั้งหมดจึงต้องถูกกำหนดโดยไม่มีชื่อโดยปริยาย

ฉันใช้ Python 3.4.3 กับ SQLAlchemy 1.0.8 และ cx_oracle 5.2

ตารางเป็นดังนี้:

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"));

รหัสที่ฉันใช้อยู่ที่ https://gist.github.com/toyg/9fb541ff3dbc8c175329 แต่แก่นของมันคือสิ่งนี้ (smeta และ dmeta เป็นข้อมูลเมตาต้นทางและเป้าหมายที่ถูกผูกไว้):

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)

มันล้มเหลวด้วยข้อผิดพลาดนี้:

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)']

นี่เป็นเพราะว่า SQLAlchemy พยายามสร้างดัชนี Unique หลังจากสร้างตาราง เมื่อมันสายเกินไปแล้ว: CREATE INDEX จำเป็นต้องมีชื่อ ดังนั้น SA จะใช้ชื่อเดียวกันกับชื่อที่มีอยู่ แต่ล้มเหลว

ฉันพยายามตั้งชื่อดัชนีเป็นไม่มีก่อนที่จะสร้าง เพื่อให้คำแนะนำแก่ SA แต่นั่นส่งผลให้เกิดข้อผิดพลาดเนื่องจากคาดว่าจะมีสตริงอยู่ที่นั่นตลอดเวลา

มีวิธีใดบ้างที่จะบอก SA ให้ต่อท้าย UNIQUE clause เปื้อนเลือดเข้ากับตาราง DDL ทันที


person Giacomo Lacava    schedule 13.08.2015    source แหล่งที่มา
comment
คุณกำลังพยายามโคลนข้อมูล? ถ้าสคีมาเหมือนกัน   -  person Dmitry.Samborskyi    schedule 13.08.2015
comment
ใช่ ฉันต้องคัดลอกทั้งตาราง สคีมาอาจจะเหมือนกันหรืออาจจะไม่เหมือนกันก็ได้ เห็นได้ชัดว่าปัญหาเกิดขึ้นเมื่อเป็นเช่นนั้น แต่การชนกันของชื่ออาจเกิดขึ้นได้แม้ในรูปแบบที่แตกต่างกัน   -  person Giacomo Lacava    schedule 13.08.2015
comment
คุณได้ลองอะไรแบบ constraint.name = prefix + constraint.name บ้างไหม? ในกรณีนี้ คุณจะมีชื่อของข้อจำกัด และจะแตกต่างจากข้อจำกัดที่มีอยู่   -  person pavel_form    schedule 13.08.2015
comment
ขออภัย ฉันหมายถึงการตั้งชื่อดัชนี   -  person pavel_form    schedule 13.08.2015
comment
ขอบคุณ @pavel_form ฉันไม่ได้คิดเรื่องนั้นเลย ยังคงเป็นวิธีแก้ปัญหาเล็กน้อย แต่ถ้าฉันไม่พบวิธีที่ดีกว่านี้ ฉันจะดำเนินการต่อไป   -  person Giacomo Lacava    schedule 13.08.2015


คำตอบ (1)


"UNIQUE INDEX" หมายความว่ามีการใช้โครงสร้าง Index DDL ของมันจะไม่ถูกส่งออกมาภายใน CREATE TABLE ดูเหมือนว่าคุณกำลังมองหาโครงสร้าง UniqueConstraint ดูเหมือนว่าในกรณีนี้ Oracle จะส่งคืนข้อมูลที่สะท้อนกลับเกี่ยวกับสิ่งที่คุณสร้างครั้งแรกเป็นวัตถุ UniqueConstraint เป็นวัตถุ Index ที่มีค่าไม่ซ้ำกัน=True (โครงสร้างเหล่านี้ "แตกต่าง" แต่ในแบ็กเอนด์จำนวนมาก พวกเขามีความหมายเหมือนกันและ/หรือผสมและจับคู่ และบางครั้งก็สะท้อนกลับด้วยซ้ำ ทำให้เกิดความสับสนอย่างยิ่ง)

ในตอนท้ายของวัน หากคุณต้องการให้คำหลัก UNIQUE เป็นข้อจำกัดแบบอินไลน์ คุณต้องใช้วัตถุ UniqueConstraint และคุณจะต้องลบ Index นี้ออกจากตาราง คุณอาจใช้ table.indexes.remove(index) ได้ วัตถุ Index จะไม่อยู่ใน table.constraints คุณอาจต้องการทำการ "คัดลอก" ของตารางด้วยวิธีทางโปรแกรมมากกว่าการใช้ tometadata() ลองพิจารณาการใช้อินเทอร์เฟซการตรวจสอบ โดยตรงและเพียงแค่สร้าง Table ที่คุณต้องการจากสิ่งนั้น

person zzzeek    schedule 14.08.2015