2009-02-04 15 views
8

Chcę przekonwertować następujące zapytanie na składnię LINQ. Mam wielki problem z zarządzaniem, aby to zadziałało. Próbowałem już zacząć od LINQ, ale odkryłem, że mogę mieć więcej szczęścia, jeśli napisałem to na odwrót.LINQ do SQL: Skomplikowane zapytanie z danymi zbiorczymi dla raportu z wielu tabel dla systemu zamówień

SELECT 
    pmt.guid, 
    pmt.sku, 
    pmt.name, 
    opt.color, 
    opt.size, 
    SUM(opt.qty) AS qtySold, 
    SUM(opt.qty * opt.itemprice) AS totalSales, 
    COUNT(omt.guid) AS betweenOrders 
FROM 
    products_mainTable pmt 
     LEFT OUTER JOIN 
      orders_productsTable opt ON opt.products_mainTableGUID = pmt.guid 
      LEFT OUTER JOIN orders_mainTable omt ON omt.guid = opt.orders_mainTableGUID AND 
       (omt.flags & 1) = 1 
GROUP BY 
    pmt.sku, opt.color, opt.size, pmt.guid, pmt.name 
ORDER BY 
    pmt.sku 

Końcowym wynikiem jest tabela, która pokazuje mi informacje o produkcie, jak widać powyżej. Jak napisać to zapytanie w formularzu LINQ, używając składni ze zrozumieniem?

Dodatkowo, mogę chcieć dodać dodatkowe filtry (na przykład do order_mainTable).

Oto jeden przykład, który próbowałem zrobić, i był dość blisko, ale nie jestem pewien, czy jest to "poprawny" sposób, i nie był w stanie pogrupować go według rozmiaru i koloru z zamówień_produktów.

from pmt in products_mainTable 
let Purchases = 
     from opt in pmt.orders_productsTable 
     where ((opt.orders_mainTable.flags & 1) == 1) 
     where ((opt.orders_mainTable.date_completedon > Convert.ToDateTime("01/01/2009 00:00:00"))) 
     select opt 
orderby pmt.sku 
select new { 
    pmt.guid, 
    pmt.sku, 
    pmt.name, 
    pmt.price, 
    AvgPerOrder = Purchases.Average(p => p.qty).GetValueOrDefault(0), 
    QtySold = Purchases.Sum(p => p.qty).GetValueOrDefault(), 
    SoldFor = Purchases.Sum(p => p.itemprice * p.qty).GetValueOrDefault()   
} 

* Edycja:

się być nieco bardziej wyraźne, więc można zrozumieć, co próbuję zrobić, tutaj jest kilka wyjaśnień.

Produkty są przechowywane w products_mainTable Zamówienia są przechowywane w orders_mainTable produkty, które zostały zamówione są przechowywane w orders_productsTable

Chcę utworzyć kilka raportów opartych na produktach, zamówieniach itp wiercenia do danych i znalezienia sensu bity do wyświetlenia użytkownikowi końcowemu.

W tym przypadku próbuję pokazać, które produkty zostały zakupione przez pewien czas i są najbardziej popularne. Ile sprzedano, za jaką cenę, i jaka jest wyprzedaż na zamówienie. Może nie najlepsza kolejność, ale eksperymentuję i wybrałem tę.

Wszystkie tabele mają związki z innymi tabelami. Tak więc z tabeli produktów mogę dostać się do zamówień zamówionych dla tego produktu, itp.

Największy problem, jaki mam, to zrozumienie działania LINQ, szczególnie w przypadku grupowania, agregowania danych, rozszerzeń, podzapytań itp. zabawne, ale zaczyna być frustrujące, ponieważ mam trudności ze znalezieniem szczegółowych wyjaśnień, jak to zrobić.

+2

Tego rodzaju rzeczy stają się skomplikowane i zaczynają wprowadzać wyniki wydajności. Możesz spróbować napisać widok za pomocą wstawionego SQL, a następnie wskazać LINQ w widoku. – willasaywhat

+0

Coś, o czym nie myślałem, dziękuję Rycerzowi Otchłani. –

Odpowiedz

3

Bruno, dziękuję bardzo za pomoc! FirstOrDefault() był prawdopodobnie największą pomocą. Podążając za tym, co zrobiłeś, i innym zasobem wymyśliłem te, które wydają się działać pięknie! Poniższe zapytanie LINQ dało mi prawie dokładną replikację SQL, który napisałem powyżej.

Oto inny zasób znalazłem na robi LEFT OUTER JOIN w LINQ: Blog Post

ostateczna odpowiedź:

from pmt in products_mainTable 
    join opt in orders_productsTable on pmt.guid equals opt.products_mainTableGUID into tempProducts 
    from orderedProducts in tempProducts.DefaultIfEmpty() 
    join omt in orders_mainTable on orderedProducts.orders_mainTableGUID equals omt.guid into tempOrders 
    from ordersMain in tempOrders.DefaultIfEmpty() 
    group pmt by new { pmt.sku, orderedProducts.color, orderedProducts.size } into g 
    orderby g.FirstOrDefault().sku 
    select new { 
     g.FirstOrDefault().guid, 
     g.Key.sku, 
     g.Key.size, 
     QTY = g.FirstOrDefault().orders_productsTable.Sum(c => c.qty), 
     SUM = g.FirstOrDefault().orders_productsTable.Sum(c => c.itemprice * c.qty), 
     AVG = g.FirstOrDefault().orders_productsTable.Average(c => c.itemprice * c.qty), 
     Some = g.FirstOrDefault().orders_productsTable.Average(p => p.qty).GetValueOrDefault(0), 
    } 
+0

Initri, wiele się z tego nauczyłem. Dzięki. –

5

Jestem również początkujący w LINQ. Nie wiem, czy jest to właściwy sposób grupowania według kilku pól, ale myślę, że musisz przekształcić te pola grupowania w klucz reprezentujący. Tak więc, zakładając, że wszystkie pola grupowania są łańcuchami lub ints można dokonać w następujący klucz:

 var qry = from pmt in products_mainTable 
        join opt in orders_productsTable on pmt.guid equals opt.products_mainTableGUID 
        join omt in orders_mainTable on opt.orders_mainTableGUID equals omt.guid 
        where (opt.orders_mainTable.flags & 1) == 1 
        group omt by pmt.sku + opt.price + opt.size + pmt.guid + pmt.name into g 
        orderby g.sku 
        select new 
        { 
         g.FirstOrDefault().guid, 
         g.FirstOrDefault().sku, 
         g.FirstOrDefault().name, 
         g.FirstOrDefault().color, 
         g.FirstOrDefault().price, 
         AvgPerOrder = g.Average(p => p.qty).GetValueOrDefault(0), 
         QtySold = g.Sum(p => p.qty).GetValueOrDefault(), 
         SoldFor = g.Sum(p => p.itemprice * p.qty).GetValueOrDefault() 
        }; 

Nie testowałem tego, więc proszę sprawdzić, czy to pomoże Ci w jakikolwiek sposób.

+0

Bruno, to była wielka pomoc! Dziękuję Ci. –

0

To było bardzo pomocne dla mnie, dzięki. Miałem podobny problem, który próbowałem rozwiązać tylko mój przypadek był o wiele prostszy, ponieważ nie miałem w nim żadnych złączeń. Po prostu próbowałem zgrupować jedno pole, uzyskać min innego i liczbę. (Minimum i liczyć się w tym samym zapytaniu)

Oto SQL Chciałem odtworzyć w składni Linq:

select t.Field1, min(t.Field2), COUNT(*) 
from SomeTable t 
group by t.Field1 
order by t.Field1 

Dzięki swoim poście w końcu udało się wymyślić to:

from t in SomeTable 
group t by new { t.Field1 } into g 
orderby g.Key.Field1 
select new 
{ 
    g.Key.Field1, 
    code = g.Min(c => c.Field2), 
    qty = g.Count() 
} 

który tworzy następujące SQL za kulisami:

SELECT [t1].[Field1], [t1].[value] AS [code], [t1].[value2] AS [qty] 
FROM (
    SELECT MIN([t0].[Field2]) AS [value], COUNT(*) AS [value2], [t0].[Field1] 
    FROM [SomeTable] AS [t0] 
    GROUP BY [t0].[Field1] 
    ) AS [t1] 
ORDER BY [t1].[Field1] 

doskonały, dokładnie to, co miałem loo Król do zrobienia. Kluczem dla mnie było to, że pokazałeś, że jest to możliwe w nowym {}, którego nigdy wcześniej nie rozważałem. To jest ogromne, teraz czuję, że mam znacznie lepsze zrozumienie.

+0

Terrific John! Cieszę się, że moje pytania/odpowiedzi ci pomogły. Dziękuję za podzielenie się. Muszę też powiedzieć, że uwielbiam Stack Overflow. : P –