จะปรับปรุงสคีมาฐานข้อมูลที่ไม่มีรูปแบบนี้ได้อย่างไร

ก่อนที่จะพูดถึงสคีมาและตาราง ฉันอยากจะแบ่งปันสิ่งที่ฉันพยายามทำให้สำเร็จก่อน ฉันกำลังดำเนินการเกี่ยวกับแอปพลิเคชันจัดส่ง โดยฉันมี categories อยู่บ้าง และแต่ละหมวดหมู่มี price ที่กำหนดไว้ล่วงหน้า

แต่การกำหนดราคาค่อนข้างน่าเกลียด (ขาดความสมมาตรและรูปแบบ อย่างน้อยฉันก็หาไม่เจอเลย) ฉันจะยกตัวอย่างให้คุณ:

พิจารณาหมวดหมู่ต่อไปนี้: เอกสาร, เอกสารหนัก, แล็ปท็อป, กล่องกระดาษ, กล่องกระดาษหนัก

1) เอกสาร: ใช้สำหรับเอกสารที่มีน้ำหนักเบากว่า ซึ่งมีน้ำหนักต่ำกว่า 0.5 กก. ราคาอยู่ที่ 20$ คงที่

[ราคาที่เก็บไว้ในตารางราคา: 20.00]

เช่น. สำหรับรายการ 300 กรัม ราคาจะอยู่ที่ 20$

2) เอกสารหนัก: สำหรับเอกสารที่มีน้ำหนักเกิน 0.5 กก. ต่างจากหมวดเอกสารตรงที่ไม่มีราคาตายตัว! แต่มีราคาต่อหน่วย: 10$ ต่อกิโลกรัม ซึ่งจะใช้กับน้ำหนักแต่ละกิโลกรัม ยกเว้น/หลัง 0.5 กิโลกรัม

[ราคาที่เก็บไว้ในตารางราคา: 10.00]

เช่น. สำหรับสินค้าขนาด 2 กิโลกรัม ราคาจะอยู่ที่ 35$ (1.5g = 15$ + 0.5 = 20$)

3) แล็ปท็อป: ตรงไปตรงมา 100$ ไม่มีอะไรพิเศษเกี่ยวกับเรื่องนี้ ไม่มีข้อจำกัดใดๆ

[ราคาที่เก็บไว้ในตารางราคา: 100.00]

เช่น. สำหรับสินค้าขนาด 2 กิโลกรัม ราคาจะอยู่ที่ 35$ (1.5g = 15$ + 0.5 = 20$)

4) กล่อง: สิ่งที่น่าสนใจมาถึงแล้ว จนถึงขณะนี้มีเพียงการพึ่งพาเดียวเท่านั้น: weight แต่อันนี้มีการขึ้นต่อกันเพิ่มเติม: dimension ซึ่งค่อนข้างคล้ายกับหมวดหมู่เอกสาร สำหรับกล่องที่มีขนาดต่ำกว่า 3 ลูกบาศก์ฟุต (CF) ราคาคือ 80$ ต่อ CF ความแตกต่างระหว่างประเภทเอกสารและกล่องก็คือ เอกสารมีราคาคงที่ ในขณะที่กล่องมีราคาต่อหน่วย แต่เดี๋ยวก่อนยังมีอีกมาก มีข้อจำกัดเพิ่มเติม: อัตราส่วนขนาด-น้ำหนัก ในกรณีนี้คือ 7kg per CF และหากน้ำหนักของสินค้าเกินอัตราส่วน จะมีการเรียกเก็บเงิน 5$ ของน้ำหนักส่วนเกินแต่ละกิโลกรัม มันสับสนมากฉันรู้ ตัวอย่างอาจช่วยได้:

[ราคาที่เก็บไว้ในตารางราคา: 80.00]

เช่น. สำหรับกล่องขนาด 80 กก. และ 2CF; ราคาจะอยู่ที่ 490$ นี่คือวิธีการ:

ขั้นแรก ให้คำนวณค่าใช้จ่ายปกติ: 80$*2CF = 160$ ทีนี้ ลองพิจารณาว่าจะข้าม อัตราส่วน หรือไม่: เนื่องจาก 1 CF = 7กก. ดังนั้น 2CF = 14กก. แต่น้ำหนักของสินค้าคือ 80 กก. จึง ข้ามอัตราส่วน (14 กก.)

เนื่องจากข้ามอัตราส่วน สำหรับกิโลกรัมพิเศษทั้งหมด (80-14 = 66 กก.) แต่ละกิโลกรัมจะมีราคา 5$: 66*5 = 330$ หลังจากเพิ่มด้วยค่าบริการปกติแล้ว: 330$+160$ = 490$

5) กล่องหนัก: อันนี้สำหรับกล่องที่มีมิติใหญ่กว่า 3CF ความแตกต่างกับกล่องคือราคาต่อหน่วย กล่องหนักคือ 60$ ต่อ CF

[ราคาที่เก็บไว้ในตารางราคา: 60.00]

เช่น. สำหรับกล่องขนาด 80 กก. และ 5CF; ราคาจะอยู่ที่ 525$ นี่คือวิธีการ:

ขั้นแรก ให้คำนวณค่าใช้จ่ายปกติ: 60$*5CF = 300$ ทีนี้ ลองพิจารณาว่าจะข้าม อัตราส่วน หรือไม่: เนื่องจาก 1 CF = 7กก. ดังนั้น 5CF = 35กก. แต่น้ำหนักของสินค้าคือ 80 กก. จึง ข้ามอัตราส่วน (35 กก.)

เนื่องจากข้ามอัตราส่วน สำหรับกิโลกรัมพิเศษทั้งหมด (80-35 = 45 กก.) แต่ละกิโลกรัมจะมีราคา 5$: 45*5 = 225$ หลังจากเพิ่มด้วยการเรียกเก็บเงินปกติแล้ว: 300$+225$ = 325$

หากคุณอ่านมาไกลขนาดนี้ ฉันคิดว่าฉันเชื่อว่าโครงสร้างธุรกิจมีความซับซ้อนมาก ตอนนี้เรามาดูสคีมา categories ของฉันกันดีกว่า:

+-------------------------+---------------------------------+------+-----+---------+----------------+
| 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    |                |
+-------------------------+---------------------------------+------+-----+---------+----------------+

สคีมาของตาราง prices ด้วย (เป็นตารางโพลีมอร์ฟิกโดยหวังว่าจะสร้างตาราง subcategories สักวันหนึ่ง):

+----------------+---------------------+------+-----+---------+----------------+
| 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    |                |
+----------------+---------------------+------+-----+---------+----------------+

ฉันจะปรับปรุงโครงสร้างนี้เพื่อให้สิ่งต่าง ๆ มีไดนามิกและสอดคล้องกันมากที่สุดเท่าที่จะเป็นไปได้ได้อย่างไร


person Tanmay    schedule 11.08.2018    source แหล่งที่มา
comment
ความคิดเห็นที่แตกต่างที่นี่ คำถามคือ: เป็นไปได้ไหมที่จะใช้ SQL DB แทนเอ็นจิ้นกฎ? ได้บางครั้ง แต่จะเหมาะสมที่สุดหรือแนะนำให้เลือก? พิจารณาใช้เครื่องมือกฎ - หรือบริการ (รหัสธรรมดา) - สำหรับกฎและใช้ DB สำหรับการบันทึกเพรดิเคตเท่านั้น User (USR) got price (PRI) for product (PRD) based on rule number (RNO). คุณสามารถจัดทำเอกสารกฎในระบบอื่นได้   -  person Damir Sudarevic    schedule 11.08.2018


คำตอบ (1)


ดังนั้นหากฉันต้องการส่งพัสดุ 10kg/2.99cf คุณจะต้องเรียกเก็บเงิน 240$ (3*80$) สำหรับกล่องพัสดุ หากฉันใส่พัสดุนั้นลงในกล่องที่ใหญ่กว่าเล็กน้อยและตอนนี้ต้องการส่งเป็นพัสดุ 10kg/3.01cf คุณจะเรียกเก็บเงินจากฉัน 180$(3*60$) สำหรับกล่องหนัก ในกรณีที่คุณปัดเศษขึ้นเป็น cf เต็มถัดไป สมมติว่าฉันต้องการส่งแพ็คเกจ 80kg/3CF คุณเรียกเก็บเงินจากฉัน 535$ (3*80+59*5) หากฉันใส่พัสดุเดียวกันลงในกล่องที่ใหญ่กว่าด้วย 80kg/4CF คุณจะเรียกเก็บเงินฉันเพียง 500$ (4*60+52*5)

นั่นเป็นสัญญาณที่ดีอย่างแท้จริง "ว่าโครงสร้างธุรกิจมีความซับซ้อนมาก" (แม้ว่าสิ่งเหล่านั้นอาจเป็นเพียงค่าตัวอย่าง แต่ก็แสดงให้เห็นถึงศักยภาพที่จะทำให้สิ่งต่างๆ ซับซ้อนเกินไป)

อย่างไรก็ตาม ฉันอาจจะเข้ารหัสเงื่อนไขของคุณในตารางดังนี้:

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  

อาจมีข้อจำกัดด้านขนาดสำหรับเอกสารเช่นกัน (ฉันสามารถส่งบอลลูนเติมฮีเลียม 0.0kg/100cf เป็นเอกสารได้หรือไม่) แต่คุณไม่ได้ระบุไว้ การแสดงรายการเงื่อนไขในลักษณะนั้นควรทำให้ชัดเจนว่าคุณมีเงื่อนไขที่ไม่เฉพาะเจาะจงในส่วนใด

off_* ระบุออฟเซ็ต เช่น จำนวนเงินที่รวมอยู่ใน price แล้ว; p_p_kg คือ ราคาต่อกิโลกรัม สำหรับน้ำหนักที่เหลือ (ลดลงตามออฟเซ็ต) ซึ่งคล้ายคลึงกับ p_p_cf ดังนั้น กล่องหนักที่มี 80kg/4CF จะถูกคำนวณเป็น

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)

ตามที่คาดไว้ 180 + 5 * 52 + 60 = 500

ผู้ใช้จะไม่มาที่ร้านของคุณแล้วพูดว่า "ฉันต้องการส่งสิ่งนี้เป็นกล่องหนัก" เขาจะพูดว่า: "ฉันต้องเสียค่าใช้จ่ายเท่าไรในการส่งของที่มีน้ำหนัก 80 กก. มี 3 cf และไม่มีแล็ปท็อป" และเขาอาจจะคาดหวังให้คุณไม่ส่งเป็นกล่องถ้ามีน้ำหนักมาก กล่องจะถูกกว่า

ดังนั้นคุณจึงนำอินพุตนี้ (และอินพุตอื่น ๆ ที่เกี่ยวข้อง เช่น ระยะทาง) และตรวจสอบแถวทั้งหมดที่ตรงตามเงื่อนไขด้วยสิ่งที่ต้องการ

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

คุณควรกำหนดสิ่งนั้นในที่เดียว ดังนั้นจึงง่ายกว่าที่จะเพิ่มเงื่อนไขเพิ่มเติม (เช่น ระยะทาง) และข้อกำหนดอื่นๆ ที่ไม่ได้กำหนดไว้ในตารางของคุณ (เช่น การปัดเศษให้เต็ม cf หรือขั้นตอน 0.1)

คุณอาจจำเป็นต้องมีโต๊ะพร้อมบริการเพิ่มเติม เช่น การจัดส่งด่วนหรือข้ามคืน การประกันพัสดุที่มีมูลค่าสูงกว่า 500$ การจัดส่งตามเวลาที่กำหนดหรือคล้ายกัน

คุณพูดถึงหมวดหมู่ย่อยและ "ตารางราคาโพลีมอร์ฟิก" แต่ยังไม่ชัดเจนว่าคุณต้องการทำอะไรกับมัน หากคุณมีตัวอย่างที่เป็นรูปธรรมซึ่งไม่สามารถกำหนดในตารางเมทริกซ์เช่นนั้นได้ ให้เพิ่มตัวอย่างเหล่านั้น แต่คุณควรทราบด้วยว่าความเรียบง่ายเป็นสิ่งสำคัญทั้งสำหรับคุณและลูกค้า คุณคงเสียฉันไปแล้วถ้าฉันคิดว่าคุณเรียกเก็บเงินฉัน 240$ สำหรับกล่อง 10kg/2.99cf ของฉัน หากคู่แข่งของคุณคิดเงิน 200$ แม้ว่าคุณจะคิดเงินฉันเพียง 180$ สำหรับกล่องหนักก็ตาม

person Solarflare    schedule 11.08.2018
comment
...แต่ย้ำอีกครั้งว่าบริการด่วนน่าจะถูกกว่าบริการปกติของร้านนี้ - person Strawberry; 12.08.2018