Linq2Sql 查询 - 通过分组透视数据

发布于 2024-12-06 19:35:20 字数 1413 浏览 3 评论 0原文

我有以下需要在网格视图中显示的时间表数据集。目前数据集的一个片段如下所示:

SessionNum    TimeStart    TimeStop    Details
----------    ---------    --------    -------
1             08:00        09:00       Math101
1             09:00        10:00       Comp102
1             11:00        12:00       Engn101
2             08:00        09:00       Comp102
2             09:00        10:00       Math101
2             10:00        11:00       Acco103

总共有 5 个会话,我希望数据集如下所示:

TimeStart    TimeStop    Session1    Session2     ...
---------    --------    --------    --------     ---
08:00        09:00       Math101     Comp102
09:00        10:00       Comp102     Math101
10:00        11:00       -           Acco103
11:00        12:00       Engn101     -

正如您将看到的,不需要聚合函数......只是分组,但对于生活对于我来说,我似乎无法理解这一点。我有以下生成第一个数据集的 LINQ 查询:

List<TimeTable> list = db.TimeTables.OrderBy(o => o.TimeStart).OrderBy(o => o.SessionNum).ToList();

这工作正常,并生成按 SessionNum 排序的数据集,然后按 TimeStart 排序。我尝试解决此问题涉及以下查询:

var result = list.GroupBy(t => t.TimeStart).Select(s => new {
    TimeStart = s.Key,
    Session1 = s.Where(x => x.SessionNum == 1),
    Session2 = s.Where(x => x.SessionNum == 2)
});

此运行,但不幸的是没有工作。我知道需要一个GroupBy(或几个),但从现在开始我有点迷失了。我真的很感激任何帮助解决这个问题的帮助。先感谢您!

I have the following dataset for a TimeTable that needs to be displayed in a gridview. Currently a snippet of the dataset looks like this:

SessionNum    TimeStart    TimeStop    Details
----------    ---------    --------    -------
1             08:00        09:00       Math101
1             09:00        10:00       Comp102
1             11:00        12:00       Engn101
2             08:00        09:00       Comp102
2             09:00        10:00       Math101
2             10:00        11:00       Acco103

There are a total of 5 sessions, and I would like for the dataset to look like:

TimeStart    TimeStop    Session1    Session2     ...
---------    --------    --------    --------     ---
08:00        09:00       Math101     Comp102
09:00        10:00       Comp102     Math101
10:00        11:00       -           Acco103
11:00        12:00       Engn101     -

As you will see, there are no aggregate functions required...just grouping, but for the life of me I cannot seem to wrap my head around this one. I have the following LINQ query which generates the first dataset:

List<TimeTable> list = db.TimeTables.OrderBy(o => o.TimeStart).OrderBy(o => o.SessionNum).ToList();

This works fine, and generates the dataset sorted by SessionNum and then TimeStart. My attempt to solve this invlovled the following query:

var result = list.GroupBy(t => t.TimeStart).Select(s => new {
    TimeStart = s.Key,
    Session1 = s.Where(x => x.SessionNum == 1),
    Session2 = s.Where(x => x.SessionNum == 2)
});

This ran, but unfortunately did not work. I know a GroupBy (or a couple) is/are required, but I'm a bit lost from this point forward. I would really appreciate any help towards solving this. Thank you in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

懒的傷心 2024-12-13 19:35:20

您不能直接在 LINQ 中执行数据透视查询。相反,您可以创建一个如下结构:

var record = new
{
    TimeStart = "10:00",
    TimeStop = "11:00",
    Sessions = new [] { "-", "Acco103", },
};

当您拥有这些记录的列表时,您必须确保 Sessions 属性是数组,其长度与整个记录中的不同会话数相同。一组数据。然后您可以通过索引到数组来访问会话信息。

查看查询后这应该更有意义。

首先,在数据库中查询所需的数据:

var query =
    from s in db.TimeTables
    orderby s.TimeStop
    orderby s.TimeStart
    group s by new { s.TimeStart, s.TimeStop } into gss
    select new
    {
        gss.Key.TimeStart,
        gss.Key.TimeStop,
        Sessions = gss.ToArray(),
    };

现在确定不同的会话集:

var sessionNums =
    db.TimeTables
        .Select(s => s.SessionNum)
        .Distinct()
        .OrderBy(n => n)
        .ToArray();

现在在内存中处理此数据(请注意 query 上的 .ToArray() 调用):

var process =
    from q in query.ToArray()
    let lookup = q.Sessions
        .ToLookup(s => s.SessionNum, s => s.Details)
    select new
    {
        q.TimeStart,
        q.TimeStop,
        Sessions = sessionNums
            .Select(n => String.Join(
                ", ",
                lookup[n].DefaultIfEmpty("-")))
            .ToArray(),
    };

这就是辛苦的地方。 查找创建了一种简单的方法来获取任何SessionNum的会话详细信息。调用 lookup[n].DefaultIfEmpty("-") 可确保每个会话至少有一个值。 String.Join 确保如果源数据同时具有同一会话编号的两个会话,我们最终会得到一个值。

无论有多少会话,这个结果都是安全的,因为它只会扩展数组。

process 查询的输出如下所示:

process-dump

然后您可以执行此查询:

var result =
    from p in process
    select new
    {
        p.TimeStart,
        p.TimeStop,
        Session1 = p.Sessions[0],
        Session2 = p.Sessions[1],
    };

这将有效地“旋转”您的结果,但您需要显式放入每个“SessionX”属性。

result 查询的输出如下所示:

result-dump

You can't directly do a pivot query in LINQ. What you can do instead is create a structure like this:

var record = new
{
    TimeStart = "10:00",
    TimeStop = "11:00",
    Sessions = new [] { "-", "Acco103", },
};

When you have a list of these records you must ensure that the Sessions property is array that is the same length as the distinct number of sessions in your entire set of data. Then you can access the session information by indexing into the array.

This should make more sense after looking at the queries.

First, query the database for the required data:

var query =
    from s in db.TimeTables
    orderby s.TimeStop
    orderby s.TimeStart
    group s by new { s.TimeStart, s.TimeStop } into gss
    select new
    {
        gss.Key.TimeStart,
        gss.Key.TimeStop,
        Sessions = gss.ToArray(),
    };

Now determine the distinct set of sessions:

var sessionNums =
    db.TimeTables
        .Select(s => s.SessionNum)
        .Distinct()
        .OrderBy(n => n)
        .ToArray();

Now process this data in memory (note the .ToArray() call on query):

var process =
    from q in query.ToArray()
    let lookup = q.Sessions
        .ToLookup(s => s.SessionNum, s => s.Details)
    select new
    {
        q.TimeStart,
        q.TimeStop,
        Sessions = sessionNums
            .Select(n => String.Join(
                ", ",
                lookup[n].DefaultIfEmpty("-")))
            .ToArray(),
    };

This is where the hard work is. The lookup creates an easy way to get session detail out for any SessionNum. Calling lookup[n].DefaultIfEmpty("-") ensures that there is at least a single value for each session. The String.Join ensures that if the source data had two sessions for the same session number at the same time that we end up with one value.

This result is safe no matter how many sessions there are as it will just extend the arrays.

The output of the process query looks like this:

process-dump

Then you can do this query:

var result =
    from p in process
    select new
    {
        p.TimeStart,
        p.TimeStop,
        Session1 = p.Sessions[0],
        Session2 = p.Sessions[1],
    };

This will effectively "pivot" your results, but you need to explicitly put in each "SessionX" property.

The output of the result query looks like this:

result-dump

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文