2009-01-29 6 views
28

Ich habe einen linken äußeren Join (unten), der Ergebnisse wie erwartet zurückgibt. Ich muss die Ergebnisse von der "richtigen" Tabelle auf den "ersten" Treffer begrenzen. Kann ich das irgendwie machen? Momentan erhalte ich für jeden Datensatz in beiden Tabellen ein Ergebnis. Ich möchte nur ein Ergebnis aus der Tabelle links (Elemente) sehen, egal wie viele Ergebnisse ich in der rechten Tabelle (Fotos) habe.Wie Sie einen LINQ linken äußeren Join auf eine Zeile begrenzen

 var query = from i in db.items 
       join p in db.photos 
       on i.id equals p.item_id into tempPhoto 
       from tp in tempPhoto.DefaultIfEmpty() 
       orderby i.date descending 
       select new 
       { 
        itemName = i.name, 
        itemID = i.id, 
        id = i.id, 
        photoID = tp.PhotoID.ToString() 
       }; 


    GridView1.DataSource = query; 
    GridView1.DataBind(); 

Antwort

51

Dies wird die Aufgabe für Sie erledigen.

from i in db.items 
let p = db.photos.Where(p2 => i.id == p2.item_id).FirstOrDefault() 
orderby i.date descending 
select new 
{ 
    itemName = i.name, 
    itemID = i.id, 
    id = i.id, 
    photoID = p == null ? null : p.PhotoID.ToString(); 
} 

bekam ich diese SQL, wenn ich es gegen mein eigenes Modell erzeugt (und ohne den Namen und die zweiten ID-Spalten in der Projektion).

SELECT [t0].[Id] AS [Id], CONVERT(NVarChar,(
    SELECT [t2].[PhotoId] 
    FROM (
     SELECT TOP (1) [t1].[PhotoId] 
     FROM [dbo].[Photos] AS [t1] 
     WHERE [t1].[Item_Id] = ([t0].[Id]) 
     ) AS [t2] 
    )) AS [PhotoId] 
FROM [dbo].[Items] AS [t0] 
ORDER BY [t0].[Id] DESC 

Als ich für den Plan gefragt, zeigte sich, dass die Unterabfrage von diesem beitreten implementiert:

<RelOp LogicalOp="Left Outer Join" PhysicalOp="Nested Loops"> 
+0

Ich mag die Eleganz dieser Lösung, aber ich denke, dass dies eine Abfrage erstellen kann, die für SQL schwieriger zu optimieren ist, weil die Subauswahl –

+0

I überprüft und war sowohl mit dem generierten SQL als auch mit dem geschätzten Ausführungsplan zufrieden. Der Subselect sollte ein linker Outer Join sein. –

+1

cool jede Chance, die Sie die SQL veröffentlichen können, bin ich gespannt, es zu sehen. –

3

Was möchten Sie die Tabelle tun Gruppe ist. Der beste Weg, dies zu tun ist:

var query = from i in db.items 
       join p in (from p in db.photos 
          group p by p.item_id into gp 
          where gp.Count() > 0 
          select new { item_id = g.Key, Photo = g.First() }) 
      on i.id equals p.item_id into tempPhoto 
      from tp in tempPhoto.DefaultIfEmpty() 
      orderby i.date descending 
      select new 
      { 
       itemName = i.name, 
       itemID = i.id, 
       id = i.id, 
       photoID = tp.Photo.PhotoID.ToString() 
      }; 

Edit: Das ist David B sprechen. Ich mache das nur, weil Nick mich darum gebeten hat. Nick, bitte ändere oder entferne diesen Abschnitt, wie du es für angemessen hältst.

Das generierte SQL ist ziemlich groß. Über den Parameter wird der int 0 (der mit dem Zähler verglichen wird) übergeben.

SELECT [t0].X AS [id], CONVERT(NVarChar(MAX),(
    SELECT [t6].Y 
    FROM (
     SELECT TOP (1) [t5].Y 
     FROM [dbo].[Photos] AS [t5] 
     WHERE (([t4].Y IS NULL) AND ([t5].Y IS NULL)) OR (([t4].Y IS NOT NULL) AND ([t5].Y IS NOT NULL) AND ([t4].Y = [t5].Y)) 
     ) AS [t6] 
    )) AS [PhotoId] 
FROM [dbo].[Items] AS [t0] 
CROSS APPLY ((
     SELECT NULL AS [EMPTY] 
     ) AS [t1] 
    OUTER APPLY (
     SELECT [t3].Y 
     FROM (
      SELECT COUNT(*) AS [value], [t2].Y 
      FROM [dbo].[Photos] AS [t2] 
      GROUP BY [t2].Y 
      ) AS [t3] 
     WHERE (([t0].X) = [t3].Y) AND ([t3].[value] > @p0) 
     ) AS [t4]) 
ORDER BY [t0].Z DESC 

Der Ausführungsplan zeigt drei linke Joins. Mindestens eins ist trivial und sollte nicht gezählt werden (es bringt die Null). Hier gibt es genug Komplexität, auf die ich kein Effizienzproblem deutlich hinweisen kann. Es könnte gut laufen.

var q = from c in 
      (from s in args 
      select s).First() 
     select c; 

Rund um den letzten Teil der Abfrage:

+0

Dies kann nicht die Antwort für Linq zu SQL, aber es hat das Problem für Entity Framework mit ähnlichen resultierenden SQL gelöst. Auf der Suche nach einer besseren Lösung jetzt. –

2

Man könnte so etwas wie zu tun. Nicht sicher, ob es funktioniert oder welche Art von Wack SQL wird es erzeugen :)

Verwandte Themen