我正在研究 SQL Server 2019,并且有一个我正在尝试解决的问题,我可以将其最好地描述为“捆绑” - 最终结果是数据集显着缩小,并且需要跟踪的库存项目更少。 这是数据集的一个简单示例:
账户ID | 产品编号 |
---|---|
1000 | 10 |
1000 | 20 |
1000 | 30 |
1001 | 10 |
1001 | 20 |
1001 | 30 |
1001 | 50 |
1001 | 60 |
1001 | 70 |
1002 | 50 |
1002 | 60 |
1002 | 70 |
1003 | 80 |
1004 | 10 |
1004 | 20 |
1004 | 80 |
我创建了一个新表,其中“捆绑包”作为参考表:
捆绑包ID | 产品编号 |
---|---|
1 | 10 |
1 | 20 |
1 | 30 |
2 | 50 |
2 | 60 |
2 | 70 |
3 | 80 |
快速说明:为了使捆绑包出现在给定帐户 ID 上,捆绑包中的所有产品 ID 都必须存在。 我的目标是获得这种输出:
账户ID | 捆绑包ID | 捆绑包之外的产品数量 |
---|---|---|
1000 | 1 | 0 |
1001 | 1 | 0 |
1001 | 2 | 0 |
1002 | 2 | 0 |
1003 | 3 | 0 |
1004 | 3 | 2 |
我希望消除/审查结果集中的任何异常值,即第三列中有数字的帐户 ID =/ 0
最初,我只是在制作捆绑包所在的实际表之前尝试使用案例,然后选择将产品选择放在 CTE 中。 我的第二种方法是将每个产品名称(第一个表的另一个列部分,名称是不同的)串在一起,并将列出帐户拥有的每个产品的扩展字符串关联为 CTE 中的新列。然后,如果帐户 ID 命中每个限定符(即 PRODUCTSTRING LIKE 'Product1' 和 ProductSTRING LIKE 'Product2' ......),则满足该情况。这种方法在最好的情况下感觉不稳定,在最坏的情况下感觉它只会在不知不觉中给我提供错误的结果。
到目前为止,我能想到的唯一其他方法是计算帐户 ID 拥有的唯一产品的数量,并将其与捆绑包的唯一产品的数量相匹配,然后基于此运行案例,但即便如此,感觉就像它很快就会变得非常笨重。
我正在使用的帐户 ID/产品 ID 视图大约有 1300 行。 谁能指出我没有考虑过的方法或我缺少的工具的方向?
这首先是一种关系除法余数问题。您缺少
Account
和 Bundle
表,它们分别存储唯一值,我假设它们存在。
但是,要得到你想要的东西将非常困难,特别是考虑到问题的定义非常不明确。
如果您想知道应用单个
ProductsRemaining
后到底有多少个Bundle
,您可以执行以下操作:
Account
与 Bundle
APPLY
...AccountProduct
Account
...BundleProduct
Bundle
...AccountProduct
的内容,即存在没有匹配 BundleProduct
的 AccountProduct
。AccountProduct
的 BundleProduct
。SELECT
a.Id AS AccountId,
b.Id AS BundleId,
bp.*
FROM Account a
CROSS JOIN Bundle b
CROSS APPLY (
SELECT
COUNT(*) - COUNT(bp.ProductId) AS ProductsRemaining, COUNT(*) - COUNT(ap.ProductId) ap, count(*) c
FROM (
SELECT *
FROM AccountProduct ap
WHERE ap.AccountId = a.Id
) ap
FULL JOIN (
SELECT *
FROM BundleProduct bp
WHERE bp.BundleId = b.Id
) bp ON bp.ProductId = ap.ProductId
HAVING COUNT(*) = COUNT(ap.ProductId) -- no missing products
) bp;
从您的评论来看,当您希望能够采用
Bundle
的任何可能组合来组成产品时,问题就开始了,但我们不一定知道哪种组合。可能有多种可能的组合,有些可能是矛盾的。您可能需要某种程序语言的组合方法,尝试每种可能的捆绑组合。
例如,如果您将一个包含产品
1, 2
的捆绑包和另一个包含 2, 3
的捆绑包放在一起,会发生什么情况,对于包含产品 1, 2, 3
的帐户来说,这是一个有效的组合吗?