【问题标题】:C# Linq - handle outer join and cartesian productC# Linq - 处理外连接和笛卡尔积
【发布时间】:2018-08-11 17:39:03
【问题描述】:

您好 Stack Overflow 社区,我有一个存储过程(我无法修改,因此只能处理返回的数据),它可以返回如下数据:

Group   Code Value
===========================
GroupA  13   123
GroupA  17   456
GroupB  17   789

但是,我需要将这个结果数据处理成如下所示:

Group   Code Value
===========================
GroupA  13   123
GroupA  17   456
GroupB  17   789
GroupB  13   NULL

... 这样我最终可以在 Code 列上使用 LINQ 的 groupBy() 来获得这个结果:

Group   Code Value
===========================
GroupA  17   456
GroupB  17   789

Group   Code Value
===========================
GroupA  13   123
GroupB  13   NULL

因此,我们几乎是在使用 Group 列和 Code 列中的唯一值进行笛卡尔积,并将这些数据连接到我们的原始数据。我可以像这样在 SQL 中相当简单地做到这一点:

DECLARE @TableData table (   
    [GroupName] nvarchar(200),
    Code int,
    Value int
); 

DECLARE @CartesianProductTable table
( 
    GroupName nvarchar(200),
    Code int
);

INSERT @TableData values 
('GroupA',  13,   123),
('GroupB',  17,   456),
('GroupA',  17,   789)

INSERT 
    @CartesianProductTable
SELECT * FROM (
        SELECT DISTINCT(GroupName) FROM @TableData
    ) T1, (
        SELECT DISTINCT(Code) FROM @TableData
    ) T2

SELECT 
    c.GroupName, 
    c.Code, 
    t.Value
FROM 
    @TableData t RIGHT OUTER join 
    @CartesianProductTable c on t.GroupName = c.GroupName AND t.Code = c.Code

所以我的问题是,在我将数据作为 C# 中的 DataTable 检索后,我该如何在 Linq 中执行此操作?我想我可以像这样按 代码 列分组:

var tableDataGrouped = dataTable.AsEnumerable()
                .GroupBy(r => r.Field<int>("Code"))
                .Select(x => x.CopyToDataTable());

但它给了我这样的数据:

Group   Code Value
===========================
GroupA  17   456
GroupB  17   789

Group   Code Value
===========================
GroupA  13   123

当我需要返回的 LINQ 数据是这样的:

Group   Code Value
===========================
GroupA  17   456
GroupB  17   789

Group   Code Value
===========================
GroupA  13   123
GroupB  13   NULL

我对 LINQ 还很陌生,所以您能指出的任何提示都会有很大帮助。

【问题讨论】:

    标签: c# sql linq join datatable


    【解决方案1】:

    我认为这是一个棘手的问题,因为解决方案是您最初所期望的

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                DataTable dt = new DataTable();
                dt.Columns.Add("Group", typeof(string));
                dt.Columns.Add("Code", typeof(int));
                dt.Columns.Add("Value", typeof(int));
                dt.Columns["Value"].AllowDBNull = true;
    
                dt.Rows.Add(new object[] { "GroupA", 13,123});
                dt.Rows.Add(new object[] { "GroupA", 17,456});
                dt.Rows.Add(new object[] { "GroupB", 17,789});
    
                List<int> codes = dt.AsEnumerable().Select(x => x.Field<int>("Code")).Distinct().ToList();
                var groups = dt.AsEnumerable().GroupBy(x => x.Field<string>("Group")).ToList();
    
                foreach (var group in groups)
                {
                    foreach (int code in codes)
                    {
                        if (!group.Any(x => x.Field<int>("Code") == code))
                        {
                            dt.Rows.Add(new object[] { group.Key, code, DBNull.Value });
                        }
                    }
                }
    
            }
        }
    }
    

    【讨论】:

    • 谢谢你,这给了我我需要的输出!非常感谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    • 2021-10-12
    • 2015-10-16
    • 1970-01-01
    • 2013-01-20
    • 2021-07-17
    • 2013-01-15
    相关资源
    最近更新 更多