与多个其他列表进行比较的列表对比

4
我在寻找解决方案时没有运气,部分原因是我不确定如何最好地解释问题!希望我在这里表达清楚,但如果不清楚,请随时询问更多信息。
在顶层: 在我们的数据库中,每个客户都可以拥有多个服务。服务单独分配给客户。但是,我们需要将“组”服务合并为共同的服务组合“包”,以进行报告。
我有一个包含包定义的数据库 - 一个名为packageServices的表,简单地列出了每个PackageID和关联的ServiceID。因此,我可以检索每个包的服务列表。
从同一数据库中,我可以检索特定客户的ServiceID列表。
我试图完成的是比较为该客户检索到的ServiceID列表,并查看该组合是否与任何定义的包(即ServiceID的组合)匹配,如果匹配,则报告该客户拥有哪些包。
我正在努力知道从哪里开始比较!我想我需要首先为每个包创建某种服务ID列表(而不是我的当前KeyValuePairs(在字典中)每个包的多行?),然后遍历包并将这些服务列表与客户拥有的服务列表进行比较?
这里使用的数据类型可能不是最合适的 - 在许多情况下,我指的是“逻辑”列表而不是C#List对象 - 我可以使用适当的数据类型 :)
非常感谢任何帮助!
编辑 - 有人建议我在SQL中汇总此信息,而不是在我的C#应用程序中。这似乎是一个好主意,下面的一个答案已经让我接近。但是,有“业务规则”确定了一个包是否是较低包的“升级”或本身的包,这使事情变得非常复杂。
我越来越觉得自己承担了太多的任务!我正在尝试正确设计它,以便将来对服务或包进行的任何更改都可以轻松处理 - 这些更改不太可能但可能发生。但是,从我到目前为止看到的内容来看,硬编码选项会更容易!
编辑2 - 我一直在解决这个问题,有人建议我为每个包分配“权重”和“组”。组是为了确保客户只能从每个组中选择一个包,而权重是为了确保仅返回“最高”级别的包。与@MarceloCantos的查询一起使用,这将意味着我应该能够仅返回每个组中的“最高”权重包 - 这看起来可能符合应用程序的要求!
感谢所有提供帮助的人 - 我很惊讶回复开始迅速并且回复的质量很高。我会尝试一下,看看进展如何。

1
我们在谈论服务、包、每个服务的典型包等方面,需要考虑什么样的大小数字? - AakashM
@AakashM - 很好的观点。服务和包将始终相对较小-目前有7个服务排列成8个包装-这将增长,但不会显著增加。到目前为止,每个包中的最大服务数量为6。客户数量将增长到数千人。然而,这些“计算”只需要每月执行一次。 - JimmE
这是一个“一次性”的工作,以确定每个客户拥有哪些包裹,还是每次有人访问网站时都需要这样做?如下所示,像Dave建议的那样将数据存储在数据库中会更有意义-今天解决它,然后确保更新并且您永远不必再次解决它。 - Kirk Broadhurst
@KirkBroadhurst - 基本上这只需要每月进行一次 - 我们将检索所有客户及其所在套餐的列表,供我们自己使用,并列出每个套餐中客户数量的总列表,供我们的供应商用于向我们计费。套餐根据客户拥有的服务而每月变化 - 客户购买单独的服务,但我们从供应商那里收到的是“套餐”的账单,不幸的是! - JimmE
2个回答

3
我建议您不要试图在计算过程中确定客户订阅的套餐(“订阅”可能不是正确的词,但您知道我的意思)。我建议您在数据库中保留指示客户订阅的套餐的单独记录。每当客户添加新服务时,您使用指示已发生添加服务事件的消息,并通过更新该客户的套餐来处理该事件,其中包括任何现在因新产品而完整的套餐。

在某种程度上,我同意。我不想详细说明业务原因是为什么这样的,因为我不想让你们感到无聊 - 但这似乎与我认为我们需要实时计算这个的原因相关。非常感谢。 - JimmE
无论是无聊还是有趣,商业原因可能都不是这里讨论的重点。对我来说很难想象有哪些商业需求会要求你不能进行一些去规范化的操作,但你肯定比我更了解你的领域。如果没有这个,你可能希望像Marcelo建议的那样让数据库处理集合的计算,因为关系型数据库就是为此而建立的。手工编写SQL的替代方法是使用带有LINQ提供程序的ORM,并在LINQ中表达查询。我担心你会在这种方法上遇到规模问题,但也许你不关心规模,所以它可能有效。 - Dave Rael
我还建议,认为业务规则在指导技术解决方案的看法可能意味着您对业务实际需求做出了一些可能有效或无效的假设,或者业务正在向您推销技术解决方案,如果可以的话,您应该抵制这种做法。也许值得重新审视需求,看看是否可以确定它们并没有真正表达业务意图。 - Dave Rael

1

你可以为客户计算服务的数量,然后针对每个具有相同服务数量的套餐,计数与客户服务相匹配的服务。只有完全匹配才会产生相同的计数。

您可以在单个查询中执行此操作,尽管这可能是一个相当棘手的操作:

SELECT CustomerID, PackageID
  FROM (SELECT CustomerID, COUNT(*) AS qty
          FROM customerServices
         GROUP BY CustomerID
       ) cs
  JOIN (SELECT PackageID, COUNT(*) AS qty
          FROM packageServices
         GROUP BY PackageID
       ) ps ON cs.qty = ps.qty
 WHERE (SELECT COUNT(*)
          FROM customerServices cs2
          JOIN packageServices ps2 ON cs2.ServiceID = ps2.ServiceID
         WHERE cs2.CustomerID = cs.CustomerID
           AND ps2.PackageID = ps.PackageID
       ) = ps.qty

编辑:我可能误解了问题。如果您想要查找包含客户服务子集的软件包,则可以执行以下操作:

 ...
       ) ps ON cs.qty >= ps.qty -- Change the test
 WHERE (SELECT COUNT(*)
          FROM customerServices cs2
          JOIN packageServices ps2 ON cs2.ServiceID = ps2.ServiceID
         WHERE cs2.CustomerID = cs.CustomerID
           AND ps2.PackageID = ps.PackageID
       ) = ps.qty

编辑 2:我改变了第二种情况的逻辑,利用了这样一个事实:如果两个集合的交集与较小的集合的大小相同,则较小的集合是较大的集合的子集。


他将不得不为每个服务数量小于或等于客户端的包裹执行此操作。 - Ventsyslav Raikov
@Marcelo Cantos - 非常感谢 - 我觉得你已经很好地理解了问题,尽管我表述得不好!你说得很对,客户可能会有额外的服务不属于套餐。让我仔细考虑你的解决方案并回复,但用SQL来实现真的很有道理。 - JimmE
1
@JimmE:没问题。顺便说一下,我改变了逻辑。我意识到在测试子集时,您仍然可以使用集合计数方法 - 从而避免双重“不存在”混乱。 - Marcelo Cantos
@Bond:感谢您指出这一点。我已经修改了答案。 - Marcelo Cantos
1
@KirkBroadhurst: 我不确定你的意思是什么(或者我的最近修改是否涵盖了你的评论)。我已经使用示例数据集测试了两个版本,它们都能正确运行,但也许我漏掉了什么。 - Marcelo Cantos
@MarceloCantos - 修改:非常感谢。我没有表明的一件事是,有些包'扩展'其他包 - 即Package1包含Service1和Service2,Package2包含Service1、Service2和Service3。如果Customer1拥有服务1、2和3,您的查询将返回Package 1和Package 2(我可以理解)。我们只认为他们有一个包 - Package 2(因为它是'最佳'匹配)。我会尝试对您的查询进行一些修改,看看效果如何!再次很抱歉没有清楚地解释情况! - JimmE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接