透过Linq

时间:2011-09-15 01:19:52

标签: linq sql-server-2008 linq-to-entities pivot pivot-table

我正在使用LINQ-to-Entities,并希望执行一个支点。

例如,我有这张表:

| data1 | data2 |
+-------+-------+
|   1   |   A   |
|   1   |   B   |
|   2   |   P   |
|   2   |   Q   |
|   2   |   R   |
+---------------+

我想将其转换为以下结果:

| data1 | first | second | third |
+-------+-------+--------+-------+
|   1   |   A   |   B    | NULL  |
|   2   |   P   |   Q    |   R   |
+--------------------------------+

我想在LINQ中执行此操作,而无需进行客户端处理。

我看过这些SO帖子,但他们并没有完全解决上述情况(据我所知)。



注意 我已经尝试了下面的内容,但它抱怨我无法在无序集合上使用Skip(),并且我没有看到一种方法来对该组的折叠'data2'信息进行排序。

from item in MyTable
group item by item.data1 into g
select new
{
    data1 = g.Key,
    first = g.Skip(0).FirstOrDefault().data2,
    second = g.Skip(1).FirstOrDefault().data2,
    third = g.Skip(2).FirstOrDefault().data2,
};

2 个答案:

答案 0 :(得分:0)

嗯,这似乎有效,但我不知道它有多高效。

from item in MyTable
group item by item.data1 into g
select new
{
    data1 = g.Key,
    first = g.OrderBy(x => x.data2).Skip(0).FirstOrDefault().data2,
    second = g.OrderBy(x => x.data2).Skip(1).FirstOrDefault().data2,
    third = g.OrderBy(x => x.data2).Skip(2).FirstOrDefault().data2,
};

生成的相应SQL(来自LINQPad)是:

SELECT [t1].[data1], (
    SELECT [t5].[data2]
    FROM (
        SELECT TOP (1) [t4].[data2]
        FROM (
            SELECT [t3].[data2], [t3].[ROW_NUMBER]
            FROM (
                SELECT ROW_NUMBER() OVER (ORDER BY [t2].[data2]) AS [ROW_NUMBER], [t2].[data2]
                FROM [MyTable] AS [t2]
                WHERE [t1].[data1] = [t2].[data1]
                ) AS [t3]
            WHERE [t3].[ROW_NUMBER] > @p0
            ) AS [t4]
        ORDER BY [t4].[ROW_NUMBER]
        ) AS [t5]
    ) AS [first], (
    SELECT [t10].[data2]
    FROM (
        SELECT TOP (1) [t9].[data2]
        FROM (
            SELECT [t8].[data2], [t8].[ROW_NUMBER]
            FROM (
                SELECT ROW_NUMBER() OVER (ORDER BY [t7].[data2]) AS [ROW_NUMBER], [t7].[data2]
                FROM (
                    SELECT [t6].[data2]
                    FROM [MyTable] AS [t6]
                    WHERE [t1].[data1] = [t6].[data1]
                    ) AS [t7]
                ) AS [t8]
            WHERE [t8].[ROW_NUMBER] > @p1
            ) AS [t9]
        ORDER BY [t9].[ROW_NUMBER]
        ) AS [t10]
    ) AS [second], (
    SELECT [t15].[data2]
    FROM (
        SELECT TOP (1) [t14].[data2]
        FROM (
            SELECT [t13].[data2], [t13].[ROW_NUMBER]
            FROM (
                SELECT ROW_NUMBER() OVER (ORDER BY [t12].[data2]) AS [ROW_NUMBER], [t12].[data2]
                FROM (
                    SELECT [t11].[data2]
                    FROM [MyTable] AS [t11]
                    WHERE [t1].[data1] = [t11].[data1]
                    ) AS [t12]
                ) AS [t13]
            WHERE [t13].[ROW_NUMBER] > @p2
            ) AS [t14]
        ORDER BY [t14].[ROW_NUMBER]
        ) AS [t15]
    ) AS [third]
FROM (
    SELECT [t0].[data1]
    FROM [MyTable] AS [t0]
    GROUP BY [t0].[data1]
    ) AS [t1]

答案 1 :(得分:0)

我假设您可以在data2字段中包含三列以上的内容?

如果是这样,则无法进行查询,返回具有可变数量属性的匿名类型。您需要为data2值集返回一个数组或某种列表。

我认为这是你可以做的事情:

var query = 
    from mt in MyTable
    group mt.data2 by mt.data1 into gmts
    let d2 = gmts.ToArray()
    select new
    {
        data1 = gmts.Key,
        data2 = d2,
        length = d2.Length,
    };

var pending = query.ToArray();

var maxLength = pending.Max(p => p.length);

Func<string[], string[]> extend = xs =>
{
    var r = new string[maxLength];
    xs.CopyTo(r, 0);
    return r;
};

var results =
    from p in pending
    select new
    {
        p.data1,
        data2 = extend(p.data2),
    };

这会产生一系列匿名类型,data2数组的大小都相同,以适应任何data1字段的最大结果数。

查询仍然作为单个SQL查询执行。而内存处理速度很快。

这对你有用吗?


修改

由于您知道自己拥有固定数量的列(根据评论),因此您可以轻松更改我的results查询以满足您的要求:

var results =
    from p in pending
    let d2s = extend(p.data2)
    select new
    {
        p.data1,
        first = d2s[0],
        second = d2s[1],
        third = d2s[2],
    };