Apakah menggunakan beberapa batasan unik pada satu tabel dianggap desain yang buruk?


8

Saya melihat INSERT INTO .. ON CONFLICT (..) DO UPDATE ..sintaks PostgreSQL dan menyadari, Anda tidak dapat melakukan beberapa pemeriksaan kendala unik dengannya. Maksud saya, Anda merujuk pada indeks unik gabungan dengan nama kolom ON CONFLICT (Name, Symbol)(jika indeks unik ditentukan untuk dua kolom ini), atau Anda menggunakan kunci utama. Jika Anda menentukan dua indeks unik terpisah untuk kolom, Anda hanya dapat memeriksa satu.

CREATE TABLE student
    (Id int primary key, Name varchar(50), Symbol varchar(50),
      CONSTRAINT col1_unique UNIQUE (Name),
      CONSTRAINT col2_unique UNIQUE (Symbol)
    ); 

INSERT INTO student
    (Id, Name, Symbol)
VALUES
    (1, 'John', 'J'),
    (2, 'David', 'D'),
    (3, 'Will', 'W');

INSERT INTO student
    (Id, Name, Symbol)
VALUES
    (4, 'Jeremy', 'J')
   on conflict(Name) DO UPDATE
   set Name = 'Jeremy';

Bisa melempar kesalahan, mengatakan Jitu duplikat. Namun, contoh ini hanyalah desain yang buruk, karena Simbol harus di tabel lain dan terhubung ke tabel siswa melalui hubungan satu ke banyak. Itulah sebabnya saya bertanya-tanya, mungkin PostgreSQL on conflictdirancang dengan cara ini, karena Anda SELALU dapat menyusun ulang tabel dengan cara, di mana hanya ada satu indeks unik. Apakah benar atau ada alasan lain?

Contoh biola: http://www.sqlfiddle.com/#!17/9c0ce


Anda dapat SELALU merestrukturisasi tabel dengan cara, di mana hanya ada satu indeks unik Ada EntityA dan EntityB. Ada 2 contoh masing-masing. InstanceA instance apa pun dapat digabungkan dengan instance EntityB, jadi ada 2 kemungkinan kombinasi di mana semua instance digunakan. Salah satu kombinasi ini direalisasikan, dan Anda harus menyimpannya. Sekarang cobalah membuat skema di mana tidak ada tabel dengan 2 unik dengan semua kendala yang mencegah data ilegal.
Akina

@Akina saya melewatkan poin Anda. Jika dua entitas terhubung melalui hubungan banyak ke banyak, Anda membuat tabel tautan, menyimpan kunci asing mereka, sehingga tidak ada tabel dengan 2 indeks unik.
appl3r

Satu instance dapat digunakan hanya sekali, jadi Anda harus memiliki 2 indeks uniqie di tabel tertaut (oleh masing-masing entitas secara terpisah) untuk mencegah penggunaan instance yang sudah digunakan.
Akina

Sementara itu benar bahwa itu benar-benar merepotkan: lihat sampel dalam jawaban Michael Green. Membagi tabel sederhana menjadi 4 tabel pasti sakit kepala, pikir karena kamus sederhana, tidak seperti Anda harus memerlukan opsi "ON CONFLICT".
Walfrat

Jawaban:


8

Selalu ada Keenam, atau Kunci Domain, Bentuk Normal. Di sini setiap kolom non-kunci menjadi tabelnya sendiri. Jadi 3NF tabel T (Key, Col1, Col2, ..) menjadi T1 (Key, Col1), T2 (Key, Col2) dll. Tabel-tabel baru yang membutuhkan keunikan dapat dideklarasikan.

Saya pikir memiliki beberapa kendala unik di atas meja adalah OK, namun. Ambil contoh tabel negara. Ini akan memiliki, katakanlah, ID, nama, kode ISO, ibu kota, dan beberapa lainnya. Masing-masing dari empat yang pertama akan menjadi unik. Selain itu, jika kita ingin sistem kita bergantung pada masing-masing menjadi unik, saya percaya kita harus mendefinisikan batasan unik pada masing-masing. Ini menegakkan kebenaran tentang data yang dapat diandalkan semua konsumen.


Apakah Anda berpikir bahwa desain postgresql hanya hasil dari rabun jauh? Oracle, SQL Server, DB2 dan lainnya semuanya menyediakan cara untuk memperhitungkan semua kunci unik dalam situasi seperti itu (menggunakan MERGEpernyataan). Pg ON CONFLICT DO UPDATE hanya ditambahkan pada 9,5 dan jauh lebih terbatas.
appl3r

1
@ appl3r itu hanya detail implementasi. Anda dapat melakukannya ON CONFLICT DO NOTHINGtanpa menyebutkan kendala unik dan itu akan mempertimbangkan semuanya (dan tidak melakukan apa-apa). Ketika Anda ingin melakukannya ON CONFLICT DO UPDATE, Anda harus mendeklarasikan kolom atau batasan dan hanya satu. Pembatasan mungkin dicabut di versi mendatang.
ypercubeᵀᴹ

Saya agak bingung dengan paragraf pertama Anda. Katakanlah kita membagi tabel Student (Id, Name, Symbol) OP menjadi S1 ​​(Id, Name) dan S2 (Id, Symbol) untuk mencoba dan membuatnya menjadi DK / NF. Apa yang akan menjadi (domain dan) kendala utama pada S2, dan bagaimana mereka memastikan bahwa setiap siswa memiliki Id unik dan simbol unik?
Ilmari Karonen

1
Pertanyaannya adalah (semacam) "Jika beberapa indeks UNIQUE baik-baik saja, mengapa PostgreSQL mengharuskan indeks arbiter ditentukan ON CONFLICT ... DO UPDATEdan sayangnya jawaban ini tidak membahas titik itu.
AndreKR

@AndreKR membahas alamat (dicetak tebal): "apakah (fitur Postgres ini) dirancang dengan cara ini, karena Anda SELALU dapat merestrukturisasi tabel dengan cara, di mana hanya ada satu indeks unik?" Anda tentu dapat menambahkan jawaban lain, dengan menunjuk pada poin yang Anda sebutkan
ypercubeᵀᴹ
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.