这里的任务是定义从供应商订购物品(零件)的最佳方式(详见下文)。
表模式的相关部分(带有一些样例数据)是
项目ID NUMBER
1 Item0001
2 Item0002
3 Item0003
ID NAME DELIVERY DISCOUNT
1 Supplier0001 0 0
2 Supplier0002 0 0.025
3 Supplier0003 20 0
DELIVERY
是该供应商每次交货时收取的运费(美元)。DISCOUNT
是该供应商允许的按时付款的结算折扣(按百分比计算,即上述ID=2
为2.5%)。
SupplierItems
SUPPLIER_ID ITEM_ID PRICE
1 2 21.67
1 5 45.54
1 7 32.97
这是供应商和物品之间的多对多连接,供应商对该物品收取的价格(以美元为单位)。每个项目至少有一个供应商,但有些有不止一个。供应商可能没有项目。
PartsRequests
ID ITEM_ID QUANTITY LOCATION_ID ORDER_ID
1 59 4 2 (null)
2 89 5 2 (null)
3 42 4 2 (null)
该表是来自现场的零件订购请求,由供应商交付到现场。将任何数量的物品运送到一个站点都会收取运费。当零件被订购时,ORDER_ID
被插入到表中,所以我们只关心那些ORDER_ID IS NULL
问题是,对于每个"LOCATION",有3个最优解决方案需要提供给用户选择,那么订购这些部件的最佳方式是什么?
- 供应商数量最少的订单组合
- 总成本最低的订单组合,即每个项目的
QUANTITY*PRICE
加上每个订单的DELIVERY
之和,忽略DISCOUNT
- 作为第2项,但占
DISCOUNT
显然,我需要确定可用的订单组合,然后确定最优的订单组合变得微不足道,但我有点困在一个有效的方法来处理构建组合。
我在SQL Server 2008中使用随机数据构建了一些SQL fiddle。这个项目有100个项目,10个供应商和100个请求。这个项目有1000个项目,50个供应商和250个请求。表模式是相同的我认为解决方案必须是递归的,我建立了一个很好的表值函数来获得,但我遇到了SQL Server中递归的32个硬限制。无论如何,我对它感到不舒服,因为它更像是一种过程语言解决方案,而不是RDMS。
所以我现在在玩CTE递归。
根查询为:
SELECT DISTINCT
'' SOLUTION_ID
,LOCATION_ID
,SUPPLIER_ID
,(subquery I haven't quite worked out) SOLE_SUPPLIER
FROM PartsRequests pr
INNER JOIN
SupplierItems si ON pr.ITEM_ID=si.ITEM_ID
WHERE pr.ORDER_ID IS NULL
这得到了所有可以提供所需物品的供应商,当然是一个解决方案,可能不是最优的。如果供应商是该位置所需的任何产品的唯一供应商,则子查询设置一个标志;如果是这样,它们必须是任何解决方案的一部分。
递归部分是通过CTE. supplier_id <>CTE逐个移除供应商。SUPPLIER_ID,如果它们仍然覆盖所有项目,则添加它们。SOLUTION_ID将是删除的供应商的CSV列表,部分是为了唯一标识每个解决方案,部分是为了检查,所以我得到组合而不是排列。
仍在研究细节,这次更新的目的是让社区说"耶,看起来会起作用",或者"你这个白痴,那不起作用,因为……"
谢谢
这是一个更通用的答案(不是sql),因为我认为解决这个问题需要更强大的东西。您的第一个场景是选择最少数量的供应商。这个问题可以看作是一个集合覆盖问题,因为你试图覆盖供应商每个站点的所有需求。这个问题已经是np完备的了。
你的第三种情况似乎与第二种基本相同。你只要把折扣考虑在价格里就行了,前提是你每笔订单都按时付款。
第二种情况至少是np困难的,因为我看到与设施位置问题有很多相似之处。你正试图根据供应商(设施)的价格和交货成本(开业成本)来决定使用(开放)哪些供应商(设施)来满足你的订单(需求)。
列举你可能的解决方案似乎是不可行的,因为有10个供应商,你有2^10种使用它们的可能性,内部需求的分布进一步复杂化。
我建议做一些动态规划,首先选择你必须使用的供应商(=他们是唯一提供特定产品的供应商),消除一些可能性(如果供应商成本a +交付成本a <供应商B的成本),然后尝试扩展你的可能解决方案集。线性规划也是一个有效的思路。>