Jika saya memahami skenario dengan tepat, Anda harus mendefinisikan tabel yang mempertahankan rangkaian waktu Harga ; oleh karena itu, saya setuju, ini ada hubungannya dengan aspek temporal dari database yang Anda gunakan.
Peraturan bisnis
Mari kita mulai menganalisis situasi dari level konseptual. Jadi, jika , dalam domain bisnis Anda,
- sebuah produk dibeli pada satu-ke-banyak Harga ,
- setiap Harga pembelian menjadi Lancar pada Tanggal Mulai yang tepat , dan
- yang Harga EndDate (yang menunjukkan Tanggal ketika Harga berhenti menjadi Current ) adalah sama dengan StartDate dari segera berikutnya Harga ,
maka itu artinya
- tidak ada kesenjangan antara yang berbeda Periode selama mana Harga yang sekarang (time series adalah terus menerus atau diperbantukan ), dan
- yang EndDate dari Harga adalah datum diturunkan.
The IDEF1X diagram yang ditunjukkan di Gambar 1 , meskipun sangat sederhana, menggambarkan skenario seperti:
Tata letak logis ekspositori
Dan desain tingkat logis SQL-DDL berikut, berdasarkan diagram IDEF1X tersebut, menggambarkan pendekatan yang layak yang dapat Anda sesuaikan dengan kebutuhan Anda sendiri:
-- At the physical level, you should define a convenient
-- indexing strategy based on the data manipulation tendencies
-- so that you can supply an optimal execution speed of the
-- queries declared at the logical level; thus, some testing
-- sessions with considerable data load should be carried out.
CREATE TABLE Product (
ProductNumber INT NOT NULL,
Etcetera CHAR(30) NOT NULL,
--
CONSTRAINT Product_PK PRIMARY KEY (ProductNumber)
);
CREATE TABLE Price (
ProductNumber INT NOT NULL,
StartDate DATE NOT NULL,
Amount INT NOT NULL, -- Retains the amount in cents, but there are other options regarding the type of use.
--
CONSTRAINT Price_PK PRIMARY KEY (ProductNumber, StartDate),
CONSTRAINT Price_to_Product_FK FOREIGN KEY (ProductNumber)
REFERENCES Product (ProductNumber),
CONSTRAINT AmountIsValid_CK CHECK (Amount >= 0)
);
The Price
meja memiliki PRIMARY KEY komposit terdiri dari dua kolom, yaitu, ProductNumber
(dibatasi, pada gilirannya, sebagai FOREIGN KEY yang membuat referensi untuk Product.ProductNumber
) dan StartDate
(menunjukkan yang khusus Tanggal di mana tertentu Produk dibeli di tertentu Harga ) .
Dalam hal Produk yang dibeli di berbagai Harga selama sama Day , bukan StartDate
kolom, Anda mungkin termasuk salah satu label sebagai StartDateTime
yang membuat Instan ketika diberikan Produk dibeli pada tepat Harga . KUNCI UTAMA kemudian harus dinyatakan sebagai (ProductNumber, StartDateTime)
.
Seperti yang diperagakan, tabel tersebut adalah yang biasa, karena Anda dapat mendeklarasikan operasi SELECT, INSERT, UPDATE, dan DELETE untuk memanipulasi datanya secara langsung, sehingga (a) memungkinkan menghindari pemasangan komponen tambahan dan (b) dapat digunakan di semua platform SQL utama dengan beberapa penyesuaian, jika perlu.
Sampel manipulasi data
Untuk mencontohkan beberapa operasi manipulasi yang tampaknya berguna, katakanlah Anda telah menyisipkan data berikut dalam tabel Product
dan Price
, masing-masing:
INSERT INTO Product
(ProductNumber, Etcetera)
VALUES
(1750, 'Price time series sample');
INSERT INTO Price
(ProductNumber, StartDate, Amount)
VALUES
(1750, '20170601', 1000),
(1750, '20170603', 3000),
(1750, '20170605', 4000),
(1750, '20170607', 3000);
Karena Price.EndDate
ini adalah titik data yang dapat diturunkan, maka Anda harus mendapatkannya melalui, tepatnya, tabel turunan yang dapat dibuat sebagai tampilan untuk menghasilkan rangkaian waktu "penuh", seperti yang dicontohkan di bawah ini:
CREATE VIEW PriceWithEndDate AS
SELECT P.ProductNumber,
P.Etcetera AS ProductEtcetera,
PR.Amount AS PriceAmount,
PR.StartDate,
(
SELECT MIN(StartDate)
FROM Price InnerPR
WHERE P.ProductNumber = InnerPR.ProductNumber
AND InnerPR.StartDate > PR.StartDate
) AS EndDate
FROM Product P
JOIN Price PR
ON P.ProductNumber = PR.ProductNumber;
Kemudian operasi berikut yang SELECT langsung dari pandangan itu
SELECT ProductNumber,
ProductEtcetera,
PriceAmount,
StartDate,
EndDate
FROM PriceWithEndDate
ORDER BY StartDate DESC;
memasok set hasil berikutnya:
ProductNumber ProductEtcetera PriceAmount StartDate EndDate
------------- ------------------ ----------- ---------- ----------
1750 Price time series… 4000 2017-06-07 NULL -- (*)
1750 Price time series… 3000 2017-06-05 2017-06-07
1750 Price time series… 2000 2017-06-03 2017-06-05
1750 Price time series… 1000 2017-06-01 2017-06-03
-- (*) A ‘sentinel’ value would be useful to avoid the NULL marks.
Sekarang, mari kita asumsikan bahwa Anda tertarik untuk mendapatkan seluruh Price
data untuk yang Product
diidentifikasi oleh ProductNumber
1750 pada Date
2 Juni 2017 . Melihat bahwa Price
pernyataan (atau baris) terkini atau efektif selama seluruh Interval yang berjalan dari (i) StartDate
hingga (ii) EndDate
, maka operasi DML ini
SELECT ProductNumber,
ProductEtcetera,
PriceAmount,
StartDate,
EndDate
FROM PriceWithEndDate
WHERE ProductNumber = 1750 -- (1)
AND StartDate <= '20170602' -- (2)
AND EndDate >= '20170602'; -- (3)
-- (1), (2) and (3): You can supply parameters in place of fixed values to make the query more versatile.
menghasilkan set hasil yang mengikuti
ProductNumber ProductEtcetera PriceAmount StartDate EndDate
------------- ------------------ ----------- ---------- ----------
1750 Price time series… 1000 2017-06-01 2017-06-03
yang membahas persyaratan tersebut.
Seperti yang ditunjukkan, PriceWithEndDate
tampilan memainkan peran penting dalam memperoleh sebagian besar data yang dapat diderivasi, dan dapat DIPILIH DARI dengan cara yang cukup biasa.
Dengan mempertimbangkan bahwa platform preferensi Anda adalah PostgreSQL, konten ini dari situs dokumentasi resmi berisi informasi tentang pandangan "terwujud" , yang dapat membantu untuk mengoptimalkan kecepatan eksekusi melalui mekanisme tingkat fisik, jika aspek tersebut menjadi bermasalah. Sistem manajemen basis data SQL lainnya (DBMS) menawarkan instrumen fisik yang sangat mirip, meskipun terminologi yang berbeda dapat diterapkan, misalnya, pandangan "diindeks" di Microsoft SQL Server.
Anda dapat melihat contoh kode DDL dan DML yang dibahas beraksi di biola db <> ini dan dalam Biola SQL ini .
Sumber terkait
Dalam tanya jawab ini kami membahas konteks bisnis yang mencakup perubahan Harga Produk tetapi memiliki cakupan yang lebih luas, sehingga Anda mungkin merasa tertarik.
Posting Stack Overflow ini mencakup poin yang sangat relevan mengenai jenis kolom yang menyimpan datum mata uang di PostgreSQL.
Tanggapan terhadap komentar
Ini mirip dengan pekerjaan yang saya lakukan, tetapi saya merasa jauh lebih nyaman / efisien untuk bekerja dengan tabel di mana harga (dalam hal ini) memiliki kolom tanggal mulai dan kolom tanggal berakhir - jadi Anda hanya mencari baris dengan target tanggal > = tanggal mulai dan tanggal target <= tanggal akhir. Tentu saja, jika data tidak disimpan dengan bidang tersebut (termasuk tanggal akhir 31 Desember 9999, bukan Null, di mana tidak ada tanggal akhir yang sebenarnya), maka Anda harus melakukan pekerjaan untuk memproduksinya. Saya benar-benar membuatnya berjalan setiap hari, dengan tanggal akhir = tanggal hari ini secara default. Juga, uraian saya memerlukan tanggal akhir 1 = tanggal mulai 2 dikurangi 1 hari. - @Robert Carnegie , pada 2017-06-22 20: 56: 01Z
Metode yang saya usulkan di atas membahas domain bisnis dari karakteristik yang dijelaskan sebelumnya , akibatnya menerapkan saran Anda tentang mendeklarasikan EndDate
sebagai kolom — yang berbeda dari “bidang” - dari tabel dasar yang dinamai Price
akan menyiratkan bahwa struktur logis dari database akan tidak mencerminkan skema konseptual dengan benar, dan skema konseptual harus didefinisikan dan tercermin dengan presisi, termasuk diferensiasi (1) informasi dasar dari (2) informasi yang dapat diturunkan .
Terlepas dari itu, tindakan semacam itu akan memperkenalkan duplikasi, karena EndDate
kemudian dapat diperoleh berdasarkan (a) tabel yang dapat diturunkan dan juga berdasarkan (b) tabel dasar yang dinamai Price
, dengan EndDate
kolom yang kemudian diduplikasi . Sementara itu adalah suatu kemungkinan, jika seorang praktisi memutuskan untuk mengikuti pendekatan tersebut, ia harus dengan jelas memperingatkan pengguna database tentang ketidaknyamanan dan ketidakefisienan yang ditimbulkannya. Salah satu dari ketidaknyamanan dan ketidakefisienan tersebut adalah, misalnya, kebutuhan mendesak untuk mengembangkan suatu mekanisme yang memastikan, setiap saat , bahwa setiap Price.EndDate
nilai sama dengan yang ada pada Price.StartDate
kolom baris yang langsung berturut-turut untuk Price.ProductNumber
nilai yang ada.
Sebaliknya, pekerjaan untuk menghasilkan data turunan yang dipermasalahkan seperti yang saya ajukan adalah, jujur, tidak istimewa sama sekali, dan diharuskan untuk (i) menjamin korespondensi yang benar antara tingkat abstraksi logis dan konseptual dari database dan (ii) ) memastikan integritas data, kedua aspek yang seperti disebutkan sebelumnya jelas sangat penting.
Jika aspek efisiensi yang Anda bicarakan terkait dengan kecepatan eksekusi beberapa operasi manipulasi data, maka itu harus dikelola di tempat yang tepat, yaitu, pada tingkat fisik, melalui, misalnya, strategi pengindeksan yang menguntungkan, berdasarkan pada (1) ) kecenderungan permintaan tertentu dan (2) mekanisme fisik tertentu yang disediakan oleh DBMS penggunaan. Kalau tidak, mengorbankan pemetaan konseptual-logis yang sesuai dan kompromi integritas data yang terlibat dengan mudah mengubah sistem yang kuat (yaitu, aset organisasi yang berharga) menjadi sumber daya yang tidak dapat diandalkan.
Rangkaian waktu yang terputus-putus atau terputus-putus
Di sisi lain, ada keadaan di mana mempertahankan EndDate
setiap baris dalam tabel deret waktu tidak hanya lebih nyaman dan efisien tetapi juga menuntut , meskipun tentu saja itu tergantung sepenuhnya pada persyaratan spesifik lingkungan bisnis. Salah satu contoh keadaan semacam itu muncul ketika
- baik informasi StartDate dan EndDate disimpan sebelum (dan disimpan melalui) setiap INSERTION, dan
- bisa ada Kesenjangan di tengah-tengah yang berbeda Periode selama mana Harga yang sekarang (yaitu, time series adalah terputus atau terpisah ).
Saya telah mewakili skenario tersebut dalam diagram IDEF1X yang ditampilkan pada Gambar 2 .
Dalam hal itu, ya, Price
tabel hipotetis harus dideklarasikan dengan cara yang mirip dengan ini:
CREATE TABLE Price (
ProductNumber INT NOT NULL,
StartDate DATE NOT NULL,
EndDate DATE NOT NULL,
Amount INT NOT NULL,
--
CONSTRAINT Price_PK PRIMARY KEY (ProductNumber, StartDate, EndDate),
CONSTRAINT Price_to_Product_FK FOREIGN KEY (ProductNumber)
REFERENCES Product (ProductNumber),
CONSTRAINT DatesOrder_CK CHECK (EndDate >= StartDate)
);
Dan, ya, desain DDL logis menyederhanakan administrasi di tingkat fisik, karena Anda dapat memasang strategi pengindeksan yang mencakup EndDate
kolom (yang, seperti yang ditunjukkan, dinyatakan dalam tabel dasar) dalam konfigurasi yang relatif lebih mudah .
Kemudian, operasi SELECT seperti yang di bawah ini
SELECT P.ProductNumber,
P.Etcetera,
PR.Amount,
PR.StartDate,
PR.EndDate
FROM Price PR
JOIN Product P
WHERE P.ProductNumber = 1750
AND StartDate <= '20170602'
AND EndDate >= '20170602';
dapat digunakan untuk memperoleh seluruh Price
data untuk yang Product
diidentifikasi oleh ProductNumber
1750 pada Date
tanggal 2 Juni 2017 .
prices
dibuat tabelprices_history
dengan kolom serupa. Hibernate Envers dapat mengotomatisasi ini untuk Anda