Is a dynamic pivot using LINQ possible?

2019-04-12 10:30发布

I have a T-SQL 2005 query which returns:

pid         propertyid  displayname     value
----------- ----------- --------------- ---------------
14270790    74          Low Price       1.3614
14270790    75          High Price      0
14270791    74          Low Price       1.3525
14270791    75          High Price      0
14270792    74          Low Price       1.353
14270792    75          High Price      0
14270793    74          Low Price       1.3625
14270793    75          High Price      0
14270794    74          Low Price       1.3524
14270794    75          High Price      0

What I would like to do is essentially pivot on the displayname field, hopefully producing:

pid       Low Price  High Price
14270790  1.3614     0
14270791  1.3525     0
14270792  1.353      0
14270793  1.3625     0
14270794  1.3524     0

(Not sure how the propertyid field would be output, so I left it out (was hoping it would simply sit alongside the Low Price and High Price fields, to indicate their IDs, but I don't think that will work.)

The problem is that the content of the original displayname field is dynamic - it is produced from a join with a PropertyName' table, so the number of pivoted columns is variable. It could therefore containHigh Price,Low Price,OpenandClose`, depending on what the join with that table returns.

It is, of course, relatively easy (regardless of the trouble I'm having writing the initial query!) to produce this pivot in a fixed query or stored proc. However, is it possible to get LINQ to generate a SQL query which would name each column to be produced rather than having to write a dynamic (probably in a stored proc) query which lists out the column names?

Thanks,

Matt.

3条回答
劫难
2楼-- · 2019-04-12 11:11

the code I think is like this:

var list = from table in Property
                       group table by table.pid into g
                       select new
                       {
                           pid = g.key,
                           LowPrice = g.Where(w => w.pid== g.key && w.priceType == "low").Select(s => s.value).FirstorDefault(),
                           HighPrice = g.Where(w => w.pid== g.key && w.priceType == "high").Select(s => s.value).FirstorDefault(),
                       };

Hope it can help you and have a nice day.

查看更多
爷、活的狠高调
3楼-- · 2019-04-12 11:12

This is the closest I could get, but it's not LINQ...

create table #t
(
    pointid [int],
    doublevalue [float],
    title [nvarchar](50)
)

insert into #t
    select
        distinct top 100
        v.pointid, v.doublevalue, p.title
    from [property] p
        inner join pointvalue v on p.propertyid = v.propertyid
        inner join point pt on v.pointid = pt.pointid
    where v.pointid in (select top 5 p.pointid from point p where p.instanceid = 36132)

declare @fields nvarchar(250)
set @fields = (select STUFF((SELECT N',[' + title + ']' FROM [property] FOR XML PATH('')), 1, 1, N''))
--select @fields

declare @sql nvarchar(500)
set @sql = 'select * from #t
pivot
(
    sum(doublevalue)
    for [title] in ('+@fields+')
) as alias'
--select @sql

exec (@sql)

drop table #t

The kicker is that I'm simply asking for every entry in the Property table, meaning there's a lot of columns, in the resulting pivot, which have NULL values.

查看更多
萌系小妹纸
4楼-- · 2019-04-12 11:22

I'll give you a sample with a different data (that I needed). You can adapt that to your need. Note only two linq queries are used, most of the other fluff is to convert a list into a datatable.

         var data = new[] {
                new{Student=1, Subject="English", Marks=40},
                new{Student=1, Subject="Maths", Marks=50},
                new{Student=1, Subject="Science", Marks=60},
                new{Student=1, Subject="Physics", Marks=70},
                new{Student=1, Subject="Chemistry", Marks=80},
                new{Student=1, Subject="Biology", Marks=90},
                new{Student=2, Subject="English", Marks=4},
                new{Student=2, Subject="Maths", Marks=5},
                new{Student=2, Subject="Science", Marks=6},
                new{Student=2, Subject="Physics", Marks=7},
                new{Student=2, Subject="Chemistry", Marks=8},
                new{Student=2, Subject="Biology", Marks=9}
            };

        /*Here the pivot column is the subject and the static column is student
        group the data against the static column(s)*/

        var groups = from d in data
                     group d by d.Student into grp
                     select new
                     {
                         StudentId = grp.Key,
                         Marks = grp.Select(d2 => new { d2.Subject, d2.Marks }).ToArray()
                     };


        /*get all possible subjects into a separate group*/
        var subjects = (from d in data
                        select d.Subject).Distinct();

        DataTable dt = new DataTable();

        /*for static cols*/
        dt.Columns.Add("STUDENT_ID");


        /*for dynamic cols*/
        foreach (var subject in subjects)
        {
            dt.Columns.Add(subject.ToString());
        }

        /*pivot the data into a new datatable*/
        foreach (var g in groups)
        {
            DataRow dr = dt.NewRow();
            dr["STUDENT_ID"] = g.StudentId;

            foreach (var mark in g.Marks)
            {
                dr[mark.Subject] = mark.Marks;
            }
            dt.Rows.Add(dr);
        }   
查看更多
登录 后发表回答