Berikut adalah pendekatan untuk mengelompokkan record berurutan yang memiliki tingkat yang sama, sekaligus mendeteksi perubahan.
Idenya adalah untuk bergabung sendiri dengan tabel, dan menghubungkan setiap record ke record berikutnya yang memiliki tingkatan berbeda. Ini dilakukan dengan menggunakan NOT EXISTS
kondisi dengan subquery yang berkorelasi.
LEFT JOIN
diperlukan, untuk menghindari pemfilteran record terakhir (yang memiliki tier saat ini), yang belum memiliki record berikutnya :untuk record ini, kita menggunakan COALESCE()
untuk mengatur tanggal akhir default.
SELECT
c1.day day_from,
COALESCE(c2.day, TO_DATE('2199-12-31', 'yyyy-mm-dd')) day_to,
c1.Vendor_ID,
c1.Customer_ID,
c1.rank
FROM customer_records c1
LEFT JOIN customer_records c2
ON c2.Vendor_ID = c1.Vendor_ID
AND c2.Customer_ID = c1.Customer_ID
AND c2.rank <> c1.rank
AND c2.DAY > c1.DAY
AND NOT EXISTS (
SELECT 1
FROM customer_records c3
WHERE
c3.Vendor_ID = c1.Vendor_ID
AND c3.Customer_ID = c1.Customer_ID
AND c3.rank <> c1.rank
AND c3.DAY > c1.DAY
AND c3.DAY < c2.DAY
)
Ini mengembalikan :
DAY_FROM | DAY_TO | Vendor_ID | Customer_ID | rank
:-------- | :-------- | ------------------: | ----------: | -----------------:
24-SEP-14 | 22-OCT-14 | 71047795 | 476095 | 3103
01-OCT-14 | 22-OCT-14 | 71047795 | 476095 | 3103
08-OCT-14 | 22-OCT-14 | 71047795 | 476095 | 3103
15-OCT-14 | 22-OCT-14 | 71047795 | 476095 | 3103
22-OCT-14 | 12-NOV-15 | 71047795 | 476095 | 3102
29-OCT-14 | 12-NOV-15 | 71047795 | 476095 | 3102
05-NOV-15 | 12-NOV-15 | 71047795 | 476095 | 3102
12-NOV-15 | 31-DEC-99 | 71047795 | 476095 | 3103
Sekarang kita dapat mengelompokkan catatan yang ditetapkan berdasarkan tingkat dan tanggal akhir untuk menghasilkan hasil yang diharapkan. ROW_NUMBER()
dapat memberi Anda nomor versi. Juga mudah untuk memeriksa catatan mana yang sekarang, seperti yang dijelaskan di atas.
SELECT
ROW_NUMBER() OVER(ORDER BY c2.day) version,
DECODE(c2.day, NULL, 'Y') current_flag,
MIN(c1.day) day_from,
COALESCE(c2.day, TO_DATE('2199-12-31', 'yyyy-mm-dd')) day_to,
c1.Vendor_ID,
c1.Customer_ID,
c1.rank
FROM customer_records c1
LEFT JOIN customer_records c2
ON c2.Vendor_ID = c1.Vendor_ID
AND c2.Customer_ID = c1.Customer_ID
AND c2.rank <> c1.rank
AND c2.DAY > c1.DAY
AND NOT EXISTS (
SELECT 1
FROM customer_records c3
WHERE
c3.Vendor_Id = c1.Vendor_Id
AND c3.Customer_ID = c1.Customer_ID
AND c3.rank <> c1.rank
AND c3.DAY > c1.DAY
AND c3.DAY < c2.DAY
)
GROUP BY
c1.Vendor_Id,
c1.Customer_ID,
c1.rank,
c2.day
ORDER BY
day_from
Hasil :
VERSION | CURRENT_FLAG | DAY_FROM | DAY_TO | Vendor_ID | Customer_ID | rank ------: | :----------- | :-------- | :-------- | ------------------: | ----------: | -----------------: 1 | N | 24-SEP-14 | 22-OCT-14 | 71047795 | 476095 | 3103 2 | N | 22-OCT-14 | 12-NOV-15 | 71047795 | 476095 | 3102 3 | Y | 12-NOV-15 | 31-DEC-99 | 71047795 | 476095 | 3103
Di Oracle, Anda dapat mengubah pilihan apa pun menjadi kueri gabungan menggunakan sintaks MERGE
. Anda dapat mencocokkan pada semua kolom yang diharapkan current_flag
dan day_to
, dan perbarui ini jika catatan sudah ada; lain, cukup masukkan yang baru.
MERGE INTO dimensions dim
USING (
-- above query goes here --
) cust
ON dim.DAY_FROM = cust.DAY_FROM
AND dim.vendor_id = cust.vendor_id
AND dim.Customer_ID = cust.Customer_ID
AND dim.rank = cust.rank
WHEN MATCHED THEN UPDATE SET
dim.DAY_TO = cust.DAY_TO,
dim.CURRENT_FLAG = cust.CURRENT_FLAG
WHEN NOT MATCHED THEN
INSERT (
dim.DAY_FROM,
dim.VERSION,
dim.CURRENT_FLAG,
dim.DAY_FROM,
dim.DAY_TO,
dim.vendor_id,
dim.customer_id,
dim.rank
) VALUES (
cust.DAY_FROM,
cust.VERSION,
cust.CURRENT_FLAG,
cust.DAY_FROM,
cust.DAY_TO,
cust.vendor_id,
cust.Customer_ID,
cust.rank
)