2013-12-14 3 views
3

Я не могу использовать Pivot на SQL-сервере из-за некоторых совместимых проблем, поэтому я пытаюсь сделать то же самое на уровне кода, используя LINQ TO SQL.Сводная таблица в LINQ TO SQL

У меня есть набор записей, как показано ниже.

Dates   RM  DM  LocationNum  City  State Count 
-----   --  --  -----------  ----  ----- ----- 
2013-12-13  1  1  4795   Grapevine TX  1 
2013-12-13  1  2  4796   Grapevine TX  1 
2013-12-14  2  3  4797   Grapevine TX  1 
2013-12-15  NULL NULL NULL   NULL  NULL 0 
2013-12-16  NULL NULL NULL   NULL  NULL 0 

Я пытаюсь преобразовать это в

RM DM Loc  City  2013-12-13  2013-12-14 2013-12-15 2013-12-16 
-- -- ---  ----  ----------  ---------- ---------- ---------- 
1 1 4795 City1  1    0   0   0 
1 2 4796 City2  1    0   0   0 
1 3 4797 City3  0    1   0   0 

Может ли один помочь мне в этом.

ответ

0

Вы не сможете использовать LINQ to SQL для выполнения всего запроса, потому что каждый столбец соответствует свойству в типе результата и существует неизвестное количество столбцов, поэтому нет способа определить результат тип. Что я сделал в подобных ситуациях, как это определить тип вроде этого:

public class PseudoPivotRow 
{ 
    public string RM {get; set;} 
    public string DM {get; set;} 
    public int Loc {get; set;} 
    public string City {get; set;} 
    public Dictionary<DateTime, int> CountsByDate{get; set} 
} 

CountsByDate Свойство соответствует нескольким столбцам даты в шарниром вы хотите создать, с ключом, соответствующий заголовок столбца, а значение значения в ячейке. Вы должны заполнить словарь в два этапа, потому что вы не можете создать Dictionary<T,U> в запросе LINQ to SQL.

var materializedGroups = 
    db.SourceTable 
    .GroupBy(s => new { s.RM, s.DM, s.LocationNum, s.City }, 
      s => new { s.Dates, s.Count }) 
    .ToList(); 

ToList заставляет запрос будет выполняться, так что следующая часть происходит на стороне клиента (C#) на стороне, где мы можем проецировать в словарь:

var pivotResult = 
    materializedGroups 
    .Select(mg => new PseudoPivotRow 
    { 
     RM = mg.Key.RM, 
     DM = mg.Key.DM, 
     Loc = mg.Key.LocationNum, 
     CountsByDate = mg.GroupBy(r => r.Dates, r => r.Count) 
         .ToDictionary(g => g.Key, g => g.Sum()) 
    }; 

(Вы можете сделать группировку из дат/подсчетов в первом запросе, если вы захотите, я думаю, что это намного проще написать таким образом, но производительность может быть хуже.)

Недостатком этого шаблона является то, что каждая «строка» в «поворотнике», может иметь различное количество столбцов, а порядок не определен. Если вам нужна согласованность, одна простая опция - получить список всех дат, затем перебрать pivotResult и вставить 0 для каждой даты, не содержащейся в словаре.

1

вот небольшой метод расширения, который я использую, чтобы сделать то, что вы упомянули. Thios является функцией поворота, которая принимает делегат и делает некоторую хорошую группировку, как только у него есть данные в памяти:

public static Dictionary<TKey1, Dictionary<TKey2, TValue>> Pivot<TSource, TKey1, TKey2, TValue> 
    (
     this IEnumerable<TSource> source, 
     Func<TSource, TKey1> key1Selector, 
     Func<TSource, TKey2> key2Selector, 
     Func<IEnumerable<TSource>, TValue> aggregate 
    ) 
{ 
    return source.GroupBy(key1Selector).Select(
    x => new 
    { 
     X = x.Key, 
     Y = x.GroupBy(key2Selector).Select(
     z => new 
     { 
      Z = z.Key, 
      V = aggregate(z) 
     } 
     ).ToDictionary(e => e.Z, o => o.V) 
    } 
    ).ToDictionary(e => e.X, o => o.Y); 
} 

типичное использование:

var pivotResult = itemsFromPreviousQuery.Pivot(s => s.SeasonID, 
       s => s.FundPropertyEntity.PropertyEntity.PropertyName, 
       lst => lst.Count()); 

играть с ним вокруг, чтобы найти применение tthat соответствует ytour критерии. Это довольно гибко, и я использовал его в разных сценариях, где другие методы петли сделают это почти невозможно.

[кстати] - вы можете найти более маленькие хитрости LinQ на волоске, что я начал путь назад, это один включен - здесь: What's your favourite linq method or 'trick'

Смежные вопросы