2011-02-22 8 views
1

Я пишу правильный внешний запрос на соединение в SQL Server 2005, и он работает нормально, но я не могу его преобразовать в LINQ.LINQ Right Outer Join Problem


Вот мой запрос:

select b.number, COUNT(*) AS [AudioCount] from audios a 
right join months b on DATEPART(Month, a.[RecordedDate]) = b.number 
group by number 

Пожалуйста, помогите мне преобразовать его в LINQ.

Благодарности & С уважением, Анил Saklania

EDIT: Исправленный запрос.

+0

Разве это не 'left' присоединиться? – Alex

+0

извините, это запрос – Anil

+0

выберите b.number, COUNT (*) AS [AudioCount] из аудиофайлов a править месяц месяцев b на DATEPART (месяц, a. [RecordedDate]) = b.number группа по номеру и хотите изменить в linq – Anil

ответ

0

В соответствии с некоторыми комментариями к вашему вопросу есть, вероятно, более простые способы сделать то, что вы хотите, чем переводить свой запрос в linq. Тем не менее, так же, как упражнение, вот способ, чтобы написать это:

var res = from audio in ListOfAudios 
    join month in ListOfMonths 
    on audio.RecordedDate.Month equals month.number into joinAudioMonth 
    from j in joinAudioMonth.DefaultIfEmpty() 
    group j by j.number into g 
    select new        
    { 
    number = g.Key, 
    cnt = g.Count() 
    }; 

EDIT: код выше не делает RIGHT JOIN, как вы просили, вот пересмотренный один на основе ответа Майка. Это не зависит от свойства объекта Audio (это может быть null, даже если сам объект существует). Но я нервничаю, ответ Майка в основном правильный.

var audioMonths = 
    from month in ListOfMonths 
    join audio in ListOfAudios on 
     month.number equals audio.RecordedDate.Month into monthAudioJoin 
    from joined in monthAudioJoin.DefaultIfEmpty() 
    select new 
    { 
     Month = month.number, 
     J = joined 
    }; 

var res = from audioMonth in audioMonths 
group audioMonth by audioMonth.Month into grouping 
select new 
{ 
    number = grouping.Key, 
    cnt = grouping.Count(a => a.J != null) 
};        

и вот как я тестировал:

public class Audio 
{ 
    public string someProperty {get; set;} 
    public DateTime RecordedDate {get; set; } 
} 

public class Month 
{ 
    public string someMonthProperty {get; set;} 
    public int number {get; set; } 
} 

public static void Main (string[] args) 
{ 
    var ListOfAudios = new List<Audio>() { 
     new Audio(){someProperty="test", RecordedDate=new DateTime(2011,01,01)}, 
     new Audio(){someProperty="test", RecordedDate=new DateTime(2011,01,02)}, 
     new Audio(){someProperty="test", RecordedDate=new DateTime(2011,02,01)}, 
     new Audio(){someProperty="test", RecordedDate=new DateTime(2011,02,02)}    
    };   

    var ListOfMonths = new List<Month>() { 
     new Month() {number=1, someMonthProperty="testMonth"}, 
     new Month() {number=2, someMonthProperty="testMonth"}, 
     new Month() {number=3, someMonthProperty="testMonth"} 
     // ... 
    }; 

    var audioMonths = 
     from month in ListOfMonths 
     join audio in ListOfAudios on 
      month.number equals audio.RecordedDate.Month into monthAudioJoin 
     from joined in monthAudioJoin.DefaultIfEmpty() 
     select new 
     { 
      Month = month.number, 
      J = joined 
     }; 

    var res = from audioMonth in audioMonths 
    group audioMonth by audioMonth.Month into grouping 
    select new 
    { 
     number = grouping.Key, 
     cnt = grouping.Count(a => a.J != null) 
    };        

    foreach(var r in res) 
    { 
     Console.WriteLine("{0} - {1}", r.number, r.cnt); 

    } 
+0

Это будет левое соединение .... – cjk

+0

@ck - вы правы. Я исправлял это, но Майк был быстрее. –

+0

Ах да, проверяя объект, а не свойство на объекте, вероятно, лучший способ его обработать. –

1

В зависимости от того, что вы ищете Я перевернул его, чтобы быть LEFT JOIN, но это левое соединение от нескольких месяцев до аудио. Это позволит вам вернуть отсчет нуля, когда месяц не имеет аудиозаписи. Использовали оригинальные данные тестирования paolo, чтобы проверить это.

var audioMonths = from month in ListOfMonths 
        join audio in ListOfAudios on 
         month.number equals audio.RecordedDate.Month into audioLeftJoin 
        from audio in audioLeftJoin.DefaultIfEmpty() 
        select new 
        { 
         Month = month.number, 
         AudioId = audio != null ? audio.someProperty : null //Need some property on the audio object to see if it exists 
        }; 
var monthAudioCount = from audioMonth in audioMonths 
          group audioMonth by audioMonth.Month into grouping 
          select new 
          { 
           Month = grouping.Key, 
           AudioCount = grouping.Count(audioMonth => audioMonth.AudioId != null) 
          }; 
+0

извините, снова добавили тесты для справки (я все еще редактировал ответ, но вы избили меня до него ... +1 :)) –

+0

Ах, потрясающе. Я не заметил, что их нет. –

1

Во-первых, некоторые заметки из книги: LINQ Карманный Справочник по J. & Б. Albahari:
1. Используя дополнительный от переводит к SelectMany.
2. в Статья переводится в группуJoin, когда она появляется сразу после . Присоединяется к статье.


Оба превосходных решений выше, Mike и Paolo, используют второй, дополнительный из пункта в запросе потому, что переводит к SelectMany. С помощью SelectMany «последовательность последовательностей» (последовательность аудиопоследовательностей) преобразуется в единый набор . Затем, чтобы подсчитать аудиосигналы, эта единая выходная коллекция на втором этапе сгруппирована в зависимости от месяца. В обоих вышеизложенных решениях это делается, и он работает нормально, но также требует тщательной проверки нулей.

ИСПОЛЬЗУЕТ ЕСТЕСТВЕННУЮ ИЕРАРХИЯ. Более чистым альтернативным способом является использование GroupJoin вместо SelectMany. GroupJoin дает иерархический набор результатов, а не плоский результирующий набор SelectMany. Иерархический результирующий набор не требует группировки, конечно, поэтому мы исключаем второй шаг.

Лучше всего, используя иерархический результирующий набор GroupJoin, нам не нужно проверять наличие нулей.
Таким образом, мы достигаем еще один чистый левое внешнее соединение с помощью этого кода, и заимствования данных Паоло:

static void Main(string[] args) 
{ 
    var ListOfAudios = new List<Audio>() { 
     new Audio() { someProperty = "test", RecordedDate = new DateTime(2011, 01, 01) }, 
     new Audio() { someProperty = "test", RecordedDate = new DateTime(2011, 01, 02) }, 
     new Audio() { someProperty = "test", RecordedDate = new DateTime(2011, 02, 01) }, 
     new Audio() { someProperty = "test", RecordedDate = new DateTime(2011, 02, 02) } 
     }; 

    var ListOfMonths = new List<Month>() { 
     new Month() {number=1, someMonthProperty="testMonth"},   
     new Month() {number=2, someMonthProperty="testMonth"},   
     new Month() {number=3, someMonthProperty="testMonth"}   
     }; 

    var q = from month in ListOfMonths 
         join audio in ListOfAudios on month.number equals audio.RecordedDate.Month 
         into hierarch 
         select new 
         { 
          MonthNum = month.number, 
          AudioCnt = hierarch.Count() 
         }; 

    foreach (var m in q) 
    { 
     Console.WriteLine("{0} - {1}", m.MonthNum,m.AudioCnt); 
    } 
    Console.ReadLine(); 
}