DB table 用于在 MIS 中维护产品动态价格的设计
DB table design for maintaining dynamic price of a product in MIS
我们正在为客户编写 MIS。特定产品的价格经常变化,客户需要维护价格和价格有效的日期期间。有个叫PRODUCT_PRICE
的table维持价格,DDL简单如下
CREATE TABLE `PRODUCT_PRICE` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`product_id` bigint(20) NOT NULL DEFAULT 0 COMMENT 'product id',
`price` bigint(20) NOT NULL DEFAULT 0 COMMENT 'price value in cent',
`start_date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'when this price takes effect',
`del_flag` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'mark if logically deleted',
`status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '0 new, 1 wait for audit, 2 accepted, 3 rejected',
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='product price table'
注意DDL中没有end_date
,因为正好是下一条记录的start_date
前一天,如果没有下一条记录则为无穷大
在系统中,每次有人在系统中创建或编辑某些产品的价格时,信息都会发送给管理员审核。除非管理员接受,否则更改不会生效。审核通过的PRODUCT_PRICE
篇可以再次编辑。
问题是在我们的旧设计中,PRODUCT_PRICE
的某条记录会被立即更改,status
字段被翻转为0等待审核和审计。 但这不是客户想要的。
新的要求是,除非管理员接受新的price
或start_date
,否则人们仍然可以在有人编辑后查看通过审核的价格记录。
我们应该如何重构旧的table设计来实现新的要求,即对某条记录的更改不会立即生效,除非管理员接受更改。
经过讨论,我们想出了2个解决方案。
每当有人更改系统中的 PRODUCT_PRICE
记录时,将创建包含新信息的行,并将其发送以供审核。接受后,旧的将被删除。因此,应将新列 reference_id
添加到 table 以标记要更改的某个旧记录。
新建tablePRODUCT_PRICE_TEMP
存放所有新的价格记录等待审核。接受后,更新PRODUCT_PRICE
中的某条旧记录。此解决方案还需要一个列 reference_id
来引用 PRODUCT_PRICE
中的特定行,但我们不需要删除 PRODUCT_PRICE
中的记录来更改值(只需更新)。
我们的新需求有更好的设计吗?
你的第一个解就差不多了
尝试从鸟瞰的角度看问题,从数据库模型中抽象出来。每次价格变化系统都会创建产品价格项目的新实例。 从用户的角度来看是一个变化,对于系统来说是一个新的实体。看来你已经想通了。
更重要的是 - 让我警告您不要这样做:"the old one would be deleted"。我相信背后的假设是产品价格开始日期可以是过去的。这是非常危险的,以后会导致可怕的并发症。 过去的价格变化一定是罕见的例外,不是正常情况。
当然仍然会发生,因为人们会犯错误。对于这种关键(且罕见!)的情况,您需要授予一两个高级人员(或 admin/support)在过去无需任何批准的情况下更改价格的能力。可能直接在数据库中。只是没有时间,公司每秒都在赔钱。通常,同一个人稍后会处理错误定价对客户和账单造成的所有后果。即使在这种情况下,您也不应编辑 product_price 中的行,将旧行标记为无效并创建一个从过去开始的新行。
我们正在为客户编写 MIS。特定产品的价格经常变化,客户需要维护价格和价格有效的日期期间。有个叫PRODUCT_PRICE
的table维持价格,DDL简单如下
CREATE TABLE `PRODUCT_PRICE` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`product_id` bigint(20) NOT NULL DEFAULT 0 COMMENT 'product id',
`price` bigint(20) NOT NULL DEFAULT 0 COMMENT 'price value in cent',
`start_date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'when this price takes effect',
`del_flag` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'mark if logically deleted',
`status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '0 new, 1 wait for audit, 2 accepted, 3 rejected',
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='product price table'
注意DDL中没有end_date
,因为正好是下一条记录的start_date
前一天,如果没有下一条记录则为无穷大
在系统中,每次有人在系统中创建或编辑某些产品的价格时,信息都会发送给管理员审核。除非管理员接受,否则更改不会生效。审核通过的PRODUCT_PRICE
篇可以再次编辑。
问题是在我们的旧设计中,PRODUCT_PRICE
的某条记录会被立即更改,status
字段被翻转为0等待审核和审计。 但这不是客户想要的。
新的要求是,除非管理员接受新的price
或start_date
,否则人们仍然可以在有人编辑后查看通过审核的价格记录。
我们应该如何重构旧的table设计来实现新的要求,即对某条记录的更改不会立即生效,除非管理员接受更改。
经过讨论,我们想出了2个解决方案。
每当有人更改系统中的
PRODUCT_PRICE
记录时,将创建包含新信息的行,并将其发送以供审核。接受后,旧的将被删除。因此,应将新列reference_id
添加到 table 以标记要更改的某个旧记录。新建table
PRODUCT_PRICE_TEMP
存放所有新的价格记录等待审核。接受后,更新PRODUCT_PRICE
中的某条旧记录。此解决方案还需要一个列reference_id
来引用PRODUCT_PRICE
中的特定行,但我们不需要删除PRODUCT_PRICE
中的记录来更改值(只需更新)。
我们的新需求有更好的设计吗?
你的第一个解就差不多了
尝试从鸟瞰的角度看问题,从数据库模型中抽象出来。每次价格变化系统都会创建产品价格项目的新实例。 从用户的角度来看是一个变化,对于系统来说是一个新的实体。看来你已经想通了。
更重要的是 - 让我警告您不要这样做:"the old one would be deleted"。我相信背后的假设是产品价格开始日期可以是过去的。这是非常危险的,以后会导致可怕的并发症。 过去的价格变化一定是罕见的例外,不是正常情况。
当然仍然会发生,因为人们会犯错误。对于这种关键(且罕见!)的情况,您需要授予一两个高级人员(或 admin/support)在过去无需任何批准的情况下更改价格的能力。可能直接在数据库中。只是没有时间,公司每秒都在赔钱。通常,同一个人稍后会处理错误定价对客户和账单造成的所有后果。即使在这种情况下,您也不应编辑 product_price 中的行,将旧行标记为无效并创建一个从过去开始的新行。