Batasan keunikan dengan rentang tanggal

15

Pertimbangkan pricestabel dengan kolom ini:

id         integer primary key
product_id integer -- foreign key
start_date date not null
end_date   date not null
quantity   integer
price      numeric

Saya ingin database memberlakukan aturan bahwa suatu produk hanya dapat memiliki satu harga pada jumlah tertentu dalam rentang tanggal (via where <date> BETWEEN start_date AND end_date).

Apakah kendala berbasis rentang seperti ini bisa dilakukan?

paku
sumber

Jawaban:

23

Ya, Anda bisa menggunakan EXCLUDEkendala, yang merupakan generalisasi UNIQUEkendala:

ALTER TABLE prices 
  ADD CONSTRAINT unique_price_per_product_quantity_daterange
    EXCLUDE  USING gist
    ( product_id WITH =, 
      quantity WITH =, 
      daterange(start_date, end_date, '[]') WITH &&   -- this is the crucial
    );

Batasan dapat diartikan sebagai mengatakan:

Jangan izinkan dua baris yang memiliki rentang tanggal yang sama product_id, sama quantitydan tumpang tindih ( &&).

The '[]'adalah untuk ingin semua termasuk rentang tanggal (default adalah [)untuk jenis range).

Lihat dokumentasi tentang batasan pada jenis jangkauan . Anda mungkin juga perlu menambahkan ekstensi dengan menjalankan (sekali, untuk setiap basis data tempat Anda ingin memasang ini):

CREATE EXTENSION btree_gist;
ypercubeᵀᴹ
sumber
Ini luar biasa. Saya tidak berpikir daterangeadalah persis sama karena itu eksklusif batas bawah, tapi itu mudah untuk memperbaiki. Haruskah saya benar-benar memigrasikan data saya untuk menggunakan daterangetipe kolom (dapat menjadikan itu pertanyaan terpisah jika itu lebih baik) atau apakah hal dua kolom ini masuk akal?
spike
Default dalam batas bawah inklusif dan batas atas eksklusif, jika saya ingat dengan baik. Saya akan mengedit untuk semua termasuk. Saya biasanya lebih suka default karena ini umum di aplikasi seperti hotel. (Saya masuk hotel jam 2, saya turun jam 8, menginap 6 hari.
Penghuni
Saya mungkin benar-benar dibalik yang mana ... baru tahu tentang berbagai jenis hari ini dan saya membaca dokumen!
spike
Saya tidak yakin tentang apa yang lebih disukai, 2 kolom atau satu dengan daterange. Anda dapat mengajukan pertanyaan terpisah. Itu mungkin akan tergantung pada penggunaan yang Anda inginkan, permintaan, kemudahan penggunaan (dan kebutuhan indeks). Jika ada kolom terpisah, akan lebih mudah misalnya untuk mengaktifkan indeks (product_id, start_date). Dengan daterange, itu harus menjadi indeks pada(product_id, lower(range_column))
ypercubeᵀᴹ