C#Linq-处理外部联接和笛卡尔积

时间:2018-08-11 17:39:04

标签: c# sql linq join datatable

嗨,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中执行此操作?我以为我可以按 Code 列进行分组,例如:

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还是很陌生,因此您可以指出的任何提示都将对您有很大帮助。

1 个答案:

答案 0 :(得分:0)

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

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 });
                    }
                }
            }

        }
    }
}
相关问题