C# 将列表中拆分金额的组合与指定金额匹配

C# 将列表中拆分金额的组合与指定金额匹配,c#,sql,C#,Sql,我创建了一个自动化系统,将csv文件中的详细付款与数据库中存储的内容进行匹配 报告金额和DB金额可能并不总是一对一的关系(没有可匹配的键值(它是复合键、CustNum、PaymentType、PaymentDate、PaymentTime)-我从csv文件中获得的唯一信息是CustNum、PaymentType、PaymentDate和amount)。数据库和报告是固定的,不能更改 csv文件来自对基于windows的系统的Web服务调用,DB信息存储从大型机提取的信息 CSV报告基于windo

我创建了一个自动化系统,将csv文件中的详细付款与数据库中存储的内容进行匹配

报告金额和DB金额可能并不总是一对一的关系(没有可匹配的键值(它是复合键、CustNum、PaymentType、PaymentDate、PaymentTime)-我从csv文件中获得的唯一信息是CustNum、PaymentType、PaymentDate和amount)。数据库和报告是固定的,不能更改

csv文件来自对基于windows的系统的Web服务调用,DB信息存储从大型机提取的信息

CSV报告基于windows的系统尚未收到付款处理确认的付款。没有收到确认的原因可能有很多,因为中间有许多系统,每个系统都有自己的特性

示例报告:

|---------------------|------------------|------------------|------------------|
|      CustNum        |   PaymentType    |   PaymentDate    |      Amount      |
|---------------------|------------------|------------------|------------------|
|        001          |    Electronic    |    2020-04-01    |      500.00      |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |      2005.23     |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      387.25      |
|---------------------|------------------|------------------|------------------|
|---------------------|------------------|------------------|------------------|
|      CustNum        |   PaymentType    |   PaymentDate    |      Amount      |
|---------------------|------------------|------------------|------------------|
|        001          |    Electronic    |    2020-04-01    |      500.00      |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |      2005.23     |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      387.25      |
|---------------------|------------------|------------------|------------------|
示例数据库行:

|---------------------|------------------|------------------|------------------|
|      CustNum        |   PaymentType    |   PaymentDate    |      Amount      |
|---------------------|------------------|------------------|------------------|
|        001          |    Electronic    |    2020-04-01    |      500.00      |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |      2000.00     |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |       5.23       |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      387.25      |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      147.51      |
|---------------------|------------------|------------------|------------------|
|---------------------|------------------|------------------|------------------|
|      CustNum        |   PaymentType    |   PaymentDate    |      Amount      |
|---------------------|------------------|------------------|------------------|
|        001          |    Electronic    |    2020-04-01    |      500.00      |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |      2000.00     |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |       5.23       |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |      10870.00    |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |       549.84     |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      387.25      |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      147.51      |
|---------------------|------------------|------------------|------------------|
我首先对给定的CustNum、RecordType、PaymentDate的所有记录的金额字段求和,并将其与csv上报告的金额进行比较。如果没有匹配,我会尝试匹配各个付款金额,而不是求和。这种方法更有效,因为与直接的一对一关系支付相比,分割支付似乎更多。拆分付款是指数据库保存一次付款的多条记录,但汇总后给出报告的金额

这适用于上述示例中的大多数情况,但有一种情况不适用,即对于给定的CustNum、RecordType和付款日期,DB中存在多笔分割付款

示例报告:

|---------------------|------------------|------------------|------------------|
|      CustNum        |   PaymentType    |   PaymentDate    |      Amount      |
|---------------------|------------------|------------------|------------------|
|        001          |    Electronic    |    2020-04-01    |      500.00      |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |      2005.23     |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      387.25      |
|---------------------|------------------|------------------|------------------|
|---------------------|------------------|------------------|------------------|
|      CustNum        |   PaymentType    |   PaymentDate    |      Amount      |
|---------------------|------------------|------------------|------------------|
|        001          |    Electronic    |    2020-04-01    |      500.00      |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |      2005.23     |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      387.25      |
|---------------------|------------------|------------------|------------------|
示例数据库行:

|---------------------|------------------|------------------|------------------|
|      CustNum        |   PaymentType    |   PaymentDate    |      Amount      |
|---------------------|------------------|------------------|------------------|
|        001          |    Electronic    |    2020-04-01    |      500.00      |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |      2000.00     |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |       5.23       |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      387.25      |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      147.51      |
|---------------------|------------------|------------------|------------------|
|---------------------|------------------|------------------|------------------|
|      CustNum        |   PaymentType    |   PaymentDate    |      Amount      |
|---------------------|------------------|------------------|------------------|
|        001          |    Electronic    |    2020-04-01    |      500.00      |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |      2000.00     |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |       5.23       |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |      10870.00    |
|---------------------|------------------|------------------|------------------|
|        002          |    Electronic    |    2020-04-01    |       549.84     |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      387.25      |
|---------------------|------------------|------------------|------------------|
|        003          |    Electronic    |    2020-04-01    |      147.51      |
|---------------------|------------------|------------------|------------------|
在上述示例中,2005.23的CustNum 002的报告金额不会报告为匹配金额,因为对于指定的CustNum和PaymentType,该金额既不是单一付款,也不是自该付款日期起的所有付款的总和

我认为我需要做的是从DB中查找所有的金额组合,并将这些组合与报告的值进行比较,以确定是否有任何值匹配。但如果有人有更好的解决方案,我愿意改变

以上是一个简化的示例-DB在指定的PaymentDate上,每个客户可能有10或20笔与PaymentType匹配的分割付款

考虑到我掌握的信息有限,以及报告的付款方式,我不确定最好的方法是什么


非常感谢您在这方面提供的任何指导。

对于暴力法,您可以从数据库计算所有金额组合,并查找是否有与CSV文件金额匹配的金额。假设一旦被其他字段过滤,金额的数量很小,这不应该太慢:

使用这些扩展方法:

public static bool IsEmpty<T>(this IEnumerable<T> src) => !src.Any();

public static IEnumerable<IEnumerable<T>> AllCombinations<T>(this IEnumerable<T> start) {
    IEnumerable<IEnumerable<T>> HelperCombinations(IEnumerable<T> items) {
        if (items.IsEmpty())
            yield return items;
        else {
            var head = items.First();
            var tail = items.Skip(1);
            foreach (var sequence in HelperCombinations(tail)) {
                yield return sequence; // Without first
                yield return sequence.Prepend(head);
            }
        }
    }

    return HelperCombinations(start).Skip(1);
}

对于蛮力方法,您可以从数据库计算所有金额组合,并查找是否有与CSV文件金额匹配的金额。假设一旦被其他字段过滤,金额的数量很小,这不应该太慢:

使用这些扩展方法:

public static bool IsEmpty<T>(this IEnumerable<T> src) => !src.Any();

public static IEnumerable<IEnumerable<T>> AllCombinations<T>(this IEnumerable<T> start) {
    IEnumerable<IEnumerable<T>> HelperCombinations(IEnumerable<T> items) {
        if (items.IsEmpty())
            yield return items;
        else {
            var head = items.First();
            var tail = items.Skip(1);
            foreach (var sequence in HelperCombinations(tail)) {
                yield return sequence; // Without first
                yield return sequence.Prepend(head);
            }
        }
    }

    return HelperCombinations(start).Skip(1);
}

我认为您没有提供足够的详细信息-CSV文件来自哪里?为什么它只包含同一日期的一些交易(分割付款)?我会用信息更新问题。我认为你没有提供足够的详细信息-CSV文件来自哪里?为什么它只包含同一日期的一些交易(分割付款)?我会用信息更新这个问题。谢谢。我要试试这个。到目前为止,我所看到的最多的情况是,在给定的paymentDate上,对于paymentType,每个客户大约有20笔分割付款,这是很少见的,通常情况下,这些场景中只有4到6笔。如果我理解正确,那么如果数据库只有一条记录,这也会起作用。所以我可以替换前两个检查,只做这个检查。@gheff是的,如果只有一个数据库记录在
数量中,这将起作用。这非常有效。我只需要做两个改变。我使用的是.Net 4.5.2,所以我需要编写自己的Prepend方法,第二个方法是不要跳过初始HelperCombinations调用中的第一条记录,因为在DB调用中没有返回头。我的错误是将其包含在示例中。很抱歉,由于我使用的是.net 4.5.2和visual studio 2017,因此需要进行额外编辑,以取消嵌套HelperCombinations方法。VisualStudio不喜欢它。我想这项功能是在后来的一次会议上引入的version@gheff
return
中的
Skip(1)
用于跳过从递归方法返回的第一个空
IEnumerable
。谢谢。我要试试这个。到目前为止,我所看到的最多的情况是,在给定的paymentDate上,对于paymentType,每个客户大约有20笔分割付款,这是很少见的,通常情况下,这些场景中只有4到6笔。如果我理解正确,那么如果数据库只有一条记录,这也会起作用。所以我可以替换前两个检查,只做这个检查。@gheff是的,如果只有一个数据库记录在
数量中,这将起作用。这非常有效。我只需要做两个改变。我使用的是.Net 4.5.2,所以我需要编写自己的Prepend方法,第二个方法是不要跳过初始HelperCombinations调用中的第一条记录,因为在DB调用中没有返回头。我的错误是将其包含在示例中。很抱歉,由于我使用的是.net 4.5.2和visual studio 2017,因此需要进行额外编辑,以取消嵌套HelperCombinations方法。VisualStudio不喜欢它。我想这项功能是在后来的一次会议上引入的version@gheff
return
中的
Skip(1)
用于跳过空的
IEnumerable
,这是递归方法的第一次返回。