Bagaimana cara memperbaiki skema database tanpa pola ini?

Sebelum beralih ke skema dan tabel, saya ingin berbagi apa yang ingin saya capai terlebih dahulu. Saya sedang mengerjakan semacam aplikasi kurir, di mana saya memiliki beberapa categories dan setiap kategori memiliki price yang telah ditentukan sebelumnya.

Tapi, menentukan harga agak jelek (tidak ada simetri dan pola; setidaknya, saya tidak bisa menemukannya). Saya akan memberi Anda sebuah contoh:

Pertimbangkan kategori berikut: Dokumen, Dokumen Berat, Laptop, Karton, Karton Berat.

1) Dokumen: Ini untuk dokumen yang lebih ringan, yaitu di bawah 0,5kg. Harganya $20, tetap.

[harga yang tersimpan di tabel harga: 20.00]

misalnya Untuk item seberat 300g, harganya menjadi $20.

2) Dokumen Berat: Ini untuk dokumen yang beratnya lebih dari 0,5kg. Berbeda dengan kategori Dokumen, tidak memiliki harga tetap! Sebaliknya, ini memiliki harga satuan: $10 per kg, yang akan diterapkan pada setiap kg kecuali/setelah 0,5kg.

[harga yang disimpan dalam tabel harga: 10.00]

misalnya Untuk barang seberat 2kg, harganya menjadi 35$ (1,5g = 15$ + 0,5 = 20$)

3) Laptop: Mudah, $100. Tidak ada yang istimewa dalam hal ini, tidak ada batasan apa pun.

[harga yang tersimpan di tabel harga: 100,00]

misalnya Untuk barang seberat 2kg, harganya menjadi 35$ (1,5g = 15$ + 0,5 = 20$)

4) Karton: Ini dia yang menarik. Sampai saat ini hanya ada satu ketergantungan: weight. Namun yang ini memiliki ketergantungan tambahan: dimension. Ini agak mirip dengan kategori Dokumen. Untuk karton dengan ukuran di bawah 3 Kaki Kubik (CF), harganya adalah $80 per CF. Perbedaan antara kategori Dokumen dan Karton adalah, Dokumen memiliki harga tetap sedangkan Karton memiliki Harga Satuan. Tapi tunggu, masih ada lagi. Ada batasan tambahan: rasio dimensi-berat. Dalam hal ini adalah 7kg per CF. Dan jika berat barang melebihi rasio, untuk setiap kg tambahan akan dikenakan biaya $5. Ini sangat membingungkan, saya tahu. Sebuah contoh mungkin bisa membantu:

[harga yang tersimpan di tabel harga: 80,00]

misalnya Untuk karton 80kg dan 2CF; harganya akan menjadi $490. Begini caranya:

Pertama hitung tagihan regulernya: 80$*2CF = 160$ Sekarang mari kita cari tahu apakah melewati Rasio: Karena, 1 CF = 7kg, maka 2CF = 14kg. Tapi berat barangnya 80kg, jadi melewati rasio (14kg)

Karena melintasi rasio, untuk semua kg tambahan (80-14 = 66kg), setiap kg akan berharga $5: 66*5 = $330. Setelah ditambahkan dengan tagihan reguler: 330$+160$ = 490$.

5) Karton Berat: Yang ini untuk karton yang dimensinya lebih besar dari 3CF. Bedanya dengan Karton adalah harga satuannya. Karton Berat adalah $60 per CF.

[harga yang tersimpan di tabel harga: 60,00]

misalnya Untuk karton 80kg dan 5CF; harganya akan menjadi $525. Begini caranya:

Pertama hitung tarif regulernya: 60$*5CF = 300$ Sekarang mari kita cari tahu apakah melewati Rasio: Karena, 1 CF = 7kg, maka 5CF = 35kg. Tapi berat barangnya 80kg, jadi melewati rasio (35kg)

Karena melintasi rasio, untuk semua kg tambahan (80-35 = 45kg), setiap kg akan berharga $5: 45*5 = $225. Setelah ditambahkan dengan tagihan reguler: 300$+225$ = 325$.

Jika Anda sudah membaca sejauh ini, saya rasa saya telah meyakinkan Anda bahwa struktur bisnis itu sangat rumit. Sekarang mari kita lihat skema categories saya:

+-------------------------+---------------------------------+------+-----+---------+----------------+
| Field                   | Type                            | Null | Key | Default | Extra          |
+-------------------------+---------------------------------+------+-----+---------+----------------+
| id                      | int(10) unsigned                | NO   | PRI | NULL    | auto_increment |
| name                    | varchar(191)                    | NO   |     | NULL    |                |
| created_at              | timestamp                       | YES  |     | NULL    |                |
| updated_at              | timestamp                       | YES  |     | NULL    |                |
| dim_dependency          | tinyint(1)                      | NO   |     | NULL    |                |
| weight_dependency       | tinyint(1)                      | NO   |     | NULL    |                |
| distance_dependency     | tinyint(1)                      | NO   |     | NULL    |                |
| dim_weight_ratio        | varchar(191)                    | YES  |     | NULL    |                |
| constraint_value        | decimal(8,2)                    | YES  |     | NULL    |                |
| constraint_on           | enum('weight','dim')            | YES  |     | NULL    |                |
| size                    | enum('short','regular','large') | YES  |     | regular |                |
| over_ratio_price_per_kg | decimal(8,2)                    | YES  |     | NULL    |                |
| deleted_at              | timestamp                       | YES  |     | NULL    |                |
+-------------------------+---------------------------------+------+-----+---------+----------------+

Juga skema tabel prices (ini adalah tabel polimorfik, berharap dapat membuat tabel subcategories suatu hari nanti):

+----------------+---------------------+------+-----+---------+----------------+
| Field          | Type                | Null | Key | Default | Extra          |
+----------------+---------------------+------+-----+---------+----------------+
| id             | int(10) unsigned    | NO   | PRI | NULL    | auto_increment |
| amount         | decimal(8,2)        | NO   |     | NULL    |                |
| created_at     | timestamp           | YES  |     | NULL    |                |
| updated_at     | timestamp           | YES  |     | NULL    |                |
| priceable_type | varchar(191)        | NO   | MUL | NULL    |                |
| priceable_id   | bigint(20) unsigned | NO   |     | NULL    |                |
| deleted_at     | timestamp           | YES  |     | NULL    |                |
+----------------+---------------------+------+-----+---------+----------------+

Bagaimana cara memperbaiki struktur ini agar segala sesuatunya tetap dinamis dan koheren?


person Tanmay    schedule 11.08.2018    source sumber
comment
Pendapat berbeda di sini. Pertanyaannya adalah: apakah mungkin menggunakan SQL DB dan bukan mesin aturan? Kadang-kadang ya, tapi apakah ini optimal atau disarankan?. Pertimbangkan untuk menggunakan mesin aturan -- atau layanan (kode biasa) -- untuk aturan dan gunakan DB hanya untuk mencatat predikat User (USR) got price (PRI) for product (PRD) based on rule number (RNO). Anda dapat mendokumentasikan aturan dalam sistem yang berbeda.   -  person Damir Sudarevic    schedule 11.08.2018


Jawaban (1)


Jadi jika saya ingin mengirim paket 10kg/2.99cf, Anda menagih saya 240$ (3*80$) untuk satu Karton. Jika saya memasukkan paket itu ke dalam kotak yang sedikit lebih besar dan sekarang ingin mengirimkannya sebagai paket 10kg/3.01cf, Anda akan menagih saya 180$(3*60$) untuk Karton Berat. Jika Anda mengumpulkan ke cf penuh berikutnya, anggap saja saya ingin mengirim paket 80kg/3CF; Anda menagih saya 535$ (3*80+59*5). Jika saya memasukkan paket yang sama ke dalam kotak yang lebih besar dengan 80kg/4CF, Anda hanya menagih saya 500$ (4*60+52*5).

Ini memang merupakan pertanda baik "bahwa struktur bisnis sangat rumit" (walaupun itu hanya contoh nilai, hal ini menunjukkan potensi untuk memperumit banyak hal).

Bagaimanapun, saya mungkin akan menyandikan kondisi Anda dalam tabel seperti itu:

category |max_kg|max_cf|is_laptop|price|p_p_kg|p_p_cf|off_kg|off_cf|off_rat
---------+------+------+---------+-----+------+------+------+------+--------
Document | 0.5  | null |    0    |  20 |   0  |   0  |  0   |  0   |  0     
Heavy Doc|  2   | null |    0    |  20 |  10  |   0  | 0.5  |  0   |  0   
Laptop   | null | null |    1    | 100 |   0  |   0  |  0   |  0   |  0  
Carton   | null |   3  |    0    |   0 |   5  |  80  |  0   |  0   |  7  
Heavy C. | null | null |    0    | 180 |   5  |  60  |  0   |  3   |  7  

Mungkin ada beberapa batasan ukuran untuk dokumen juga (bisakah saya mengirim 0.0kg/100cf balon berisi helium sebagai dokumen?), tetapi Anda belum menentukannya; mencantumkan kondisi seperti itu akan memperjelas di mana Anda memiliki kondisi yang tidak spesifik.

off_* menentukan offset, mis. jumlah yang sudah termasuk dalam price; p_p_kg adalah harga per kg untuk sisa berat (dikurangi offset), analog dengan p_p_cf. Jadi karton berat dengan 80kg/4CF akan dihitung sebagai

price    -- 180
+ p_p_kg * greatest(kg - off_rat * cf - off_kg, 0)  -- 5 * (80-7*4-0) 
+ p_p_cf * greatest(cf - off_cf, 0) -- 60 * (4 - 3)

jadi, seperti yang diharapkan, 180 + 5 * 52 + 60 = 500.

Pengguna tidak akan datang ke toko Anda dan berkata "Saya ingin mengirimkan ini sebagai Karton Berat". Dia akan berkata: "Berapa biaya yang harus saya keluarkan untuk mengirim sesuatu yang beratnya 80 kg, memiliki 3 cf dan tidak ada laptop." Dan dia mungkin akan mengharapkan Anda untuk tidak mengirimkannya dalam bentuk Karton jika Berat Karton akan lebih murah.

Jadi Anda mengambil masukan ini (dan masukan lain yang relevan seperti jarak) dan memeriksa semua baris yang memenuhi kondisi dengan sesuatu seperti

select (your price formula depending on input) as cost
...
where (max_kg is null or max_kg >= 80) 
  and (max_cf is null or max_cf >= 3)
  and (is_laptop is null or is_laptop = 0)
order by cost

Anda mungkin harus mendefinisikannya di satu tempat, sehingga lebih mudah untuk menambahkan kondisi tambahan (misalnya jarak) dan spesifikasi lain yang tidak ditentukan dalam tabel Anda (misalnya pembulatan ke cf penuh atau langkah 0,1).

Anda mungkin juga memerlukan meja dengan layanan tambahan seperti pengiriman ekspres atau semalam, asuransi untuk paket di atas $500, pengiriman pada waktu tetap atau serupa.

Anda menyebutkan subkategori dan "tabel harga polimorfik", tetapi tidak jelas apa yang ingin Anda lakukan dengannya. Jika Anda memiliki beberapa contoh konkrit yang tidak dapat dirumuskan dalam tabel matriks seperti itu, tambahkan saja. Namun Anda juga harus menyadari bahwa kesederhanaan adalah raja, baik bagi Anda maupun pelanggan. Anda mungkin sudah kehilangan saya jika menurut saya Anda menagih saya 240$ untuk 10kg/2.99cf Karton saya jika pesaing Anda melakukannya untuk 200$, bahkan jika Anda sebenarnya hanya menagih saya 180$ untuk Karton Berat.

person Solarflare    schedule 11.08.2018
comment
...tapi sekali lagi, layanan ekspres mungkin lebih murah daripada layanan reguler di toko ini - person Strawberry; 12.08.2018