2009-02-04 5 views
8

Ich möchte die folgende Abfrage in LINQ-Syntax konvertieren. Ich habe große Schwierigkeiten damit, es zur Arbeit zu bringen. Ich habe tatsächlich versucht, mit LINQ zu beginnen, fand aber heraus, dass ich mehr Glück haben könnte, wenn ich es anders herum schreiben würde.LINQ to SQL: Komplizierte Abfrage mit Aggregatdaten für einen Bericht aus mehreren Tabellen für ein Bestellsystem

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 

Das Endergebnis ist eine Tabelle, die mir Informationen über ein Produkt zeigt, wie Sie oben sehen können. Wie schreibe ich diese Abfrage, in LINQ-Form, mit Verständnis Syntax?

Zusätzlich möchte ich zusätzliche Filter hinzufügen (z. B. zur orders_mainTable).

Hier ist ein Beispiel, dass ich versuchte, Arbeit zu machen, und war ziemlich nahe, aber bin mir nicht sicher, ob es der "richtige" Weg ist, und war nicht in der Lage, sie nach Größe und Farbe aus der orders_productsTable zu gruppieren.

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()   
} 

* Edit:

Um ein wenig mehr explizit zu sein, damit Sie verstehen, was ich zu tun versuchen, hier einige weitere Erklärung.

Produkte in products_mainTable gespeichert sind Aufträge werden in orders_mainTable gespeichert Produkte, die in orders_productsTable gespeichert bestellt wurden

ich mehrere Berichte basierend auf Produkte, Aufträge etc. Bohren in die Daten und die Suche nach sinnvoll anlegen möchten Bits, die dem Endbenutzer angezeigt werden.

In diesem Fall versuche ich zu zeigen, welche Produkte über einen Zeitraum gekauft wurden, und sind die beliebtesten. Wie viele verkauft, für welchen Preis, und was ist der Ausbruch pro Bestellung. Vielleicht nicht die beste Reihenfolge, aber ich experimentiere nur und wählte diese aus.

Alle Tabellen haben Beziehungen zu anderen Tabellen. Also aus der Produkttabelle, ich kann zu welchen Bestellungen bestellt, dass Produkt, etc.

Das größte Problem, das ich habe, ist zu verstehen, wie LINQ funktioniert, insbesondere mit Gruppierung, Aggregat Daten, Erweiterungen, Unterabfragen, etc. Es war Spaß, aber es wird frustrierend, weil ich Schwierigkeiten habe, detaillierte Erklärungen dazu zu finden.

+2

Diese Art von Sache ist, wo LINQ kompliziert wird und beginnt, Leistungstreffer einzuführen. Sie könnten versuchen, eine Sicht mit dem von Ihnen geposteten SQL zu schreiben, und dann auf LINQ in der Ansicht zeigen. – willasaywhat

+0

Etwas, an das ich nicht gedacht habe, danke Abyss Knight. –

Antwort

3

Bruno, vielen Dank für Ihre Hilfe! Der FirstOrDefault() war wahrscheinlich die größte Hilfe. Nach etwas von dem, was Sie getan haben, und einer anderen Ressource habe ich folgendes gefunden, das wunderbar zu funktionieren scheint! Diese LINQ-Abfrage unten gab mir fast eine exakte Replikation der oben angegebenen SQL.

Hier ist die andere Ressource, die ich auf dem Tun ein LEFT OUTER JOIN in LINQ gefunden: Blog Post

abschließende Antwort: Dank mir

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

Intiri, ich habe auch viel damit gelernt. Vielen Dank. –

5

Ich bin auch ein Anfänger in LINQ. Ich weiß nicht, ob dies der richtige Weg für die Gruppierung nach mehreren Feldern ist, aber ich denke, Sie müssen diese Gruppierungsfelder in einen repräsentativen Schlüssel umwandeln. Also, vorausgesetzt, dass alle Ihre Gruppierung Felder sind Strings oder ints können Sie einen Schlüssel machen, wie folgt:

 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() 
        }; 

ich nicht testen dies so sehen Sie, wenn Sie das in irgendeiner Weise hilft.

+0

Bruno, das war eine große Hilfe! Vielen Dank. –

0

Das war sehr hilfreich. Ich hatte ein ähnliches Problem, das ich versuchte zu sortieren, nur mein Fall war viel einfacher, da ich keine Joins hatte. Ich habe einfach versucht, ein Feld zu gruppieren, das Min eines anderen zu bekommen und den Count. (Min und zählen in der gleichen Abfrage)

Hier ist die SQL ich in Linq-Syntax erstellen wollte:

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

Dank Ihrer Post habe ich mit diesem schließlich geschafft zu kommen:

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() 
} 

welche der folgenden SQL hinter den Kulissen erzeugt:

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] 

Perfect, genau das, was ich war loo König zu tun. Der Schlüssel für mich war, dass Sie gezeigt haben, dass es möglich ist, dies innerhalb des neuen {} zu tun, was ich nie in Betracht gezogen hätte. Das ist riesig. Ich habe jetzt das Gefühl, dass ich ein besseres Verständnis für die Zukunft habe.

+0

Schrecklicher John! Ich bin froh, dass meine Fragen/Antworten dir geholfen haben. Ich danke Ihnen für das Teilen. Ich muss auch sagen, ich liebe Stack Overflow. : P –