2011-08-01 18 views
0

私は2つのオブジェクト(テーブル)AとBを結合する必要があります。任意のAについては、0〜多くのBがあります。クエリは、Aごとに1つの行を返す必要があります。Linqを使って "複雑な"結合を実行する方法

B条件の後にBから必要な行を選択できるように、結合の前に注文したいと思います。 Bに列タイプがあるとします。タイプ1がある場合、それは私が必要とするBだ、そうでない場合:タイプ2を選択しなければならない、など

今、私はそれについて考える、私もT-SQLで、私はこれにする方法を確認していません。

SELECT A.* 
FROM A LEFT JOIN (
    SELECT * FROM B AS B1 WHERE B1.Type = (SELECT TOP 1 B2.Type FROM B AS B2 
             WHERE B2.JoinID = B1.JoinID 
             ORDER BY B2.Type) 
) AS B ON B.JoinID = A.JoinID 

[編集]

私はそれを動作させるために試してみたsgtzの答えを: 私はこのような何かを考えます。注文したいフィールドが存在しないため、追加のステップを踏む必要がある場合。私はステップ1でこのフィールドを追加します。ステップ2では、キーを選択してステップ3ですべてを結合しますが、そこにエラーが表示されます。「結合句の式のタイプが正しくありません。 'GroupJoin'への呼び出し。 " 「新しい{b.TopRelatieID上adressen1に参加...」

var adressen1 = from a in db.Adres 
        select new 
        { 
         RelatieAdres = a, 
         Sortering = (int)(a.AdresType.Code == codeVestAdres ? 
              1 : a.AdresType.Code == codePostAdres ? 
               2 : (100 + (int)a.AdresType.Code.ToCharArray()[0])) 
        }; 

    var adressen2 = from b in adressen1 
        group b by new { RelatieID = b.RelatieAdres.RelatieID } into p 
        let TopAdresType = p.Min(at => at.Sortering) 
        select new { TopRelatieID = p.Key.RelatieID, TopAdresType }; 

    var q = from k in db.Klants 
      join b in adressen2 on k.RelatieID equals b.TopRelatieID into b_join 
      from b in b_join.DefaultIfEmpty() 
      join a in adressen1 on new { b.TopRelatieID, b.TopAdresType } equals new { a.RelatieAdres.RelatieID, a.Sortering } into a_join 
      from a in a_join.DefaultIfEmpty() 
+0

この問合せでは、Aのすべての行を返すだけです。B行の行が1行または複数回取得され、その行に接続され、WHERE条件を満たします。 .. –

+0

@Stefan:あなたに答えを投稿しました。 – sgtz

+0

@MichaelSagalovichそれは奇妙に聞こえるかもしれませんが、目的が何であるか説明していないのです。 A =顧客およびB =住所。私はすべての顧客が1つの住所しか持たない場合は住宅住所が存在する場合はそれを、それ以外の場合は住所を指定します。 –

答えて

0

これは実際の例です。私はそれを2段階でやった。

[Test] 
    public void Test333() 
    { 
     List<Order> O; 
     var M = Prepare333Data(out O); 

     var OTop = from o in O 
        group o by new {id=o.id, orderid=o.orderid} 
        into p 
        let topType = p.Min(tt => tt.type) 
        select new Order(p.Key.id, p.Key.orderid, topType); 

     var ljoin = from m in M 
        join t in OTop on m.id equals t.id into ts 
        from u in ts.DefaultIfEmpty() 
        select new {u.id, u.orderid, u.type}; 
    } 

    public class Manufacturer 
    { 
     public Manufacturer(int id, string name) 
     { 
      this.id = id; 
      this.name = name; 
     } 

     public int id { get; set; } 
     public string name { get; set; } 
    } 

    public class Order 
    { 
     public Order(int id, int orderid, int type) 
     { 
      this.orderid = orderid; 
      this.id = id; 
      this.type = type; 
     } 

     public int orderid { get; set; } 
     public int id { get; set; } 
     public int type { get; set; } 
    } 


    private List<Manufacturer> Prepare333Data(out List<Order> O) 
    { 
     var M = new List<Manufacturer>() {new Manufacturer(1, "Abc"), new Manufacturer(2, "Def")}; 
     O = new List<Order>() 
       { 
        new Order(1, 1, 2), 
        new Order(1, 2, 2), 
        new Order(1, 2, 3), 
        new Order(2, 3, 1) 
        , 
        new Order(2, 3, 1) 
        , 
        new Order(2, 3, 2) 
       }; 
     return M; 
    } 

コメントへの応答:

あなたの "{新しい" 新しい匿名型を作成します。差分プロセスによって作成された2つの匿名型は、型が同じ順序で宣言され、同じ型定義を持つ場合(つまり、intがintに一致し、intがshortに一致しない場合)、同じシグネチャを持つと言われます。私はこのシナリオをLINQで広範にテストしていません。

私は実際の具体的なクラスで作業していましたが、JOIN部分にはアノテーションの種類がありませんでした。おそらく純粋なLINQでそれを再加工する方法がありますが、それはまだであるか分からない。私は大丈夫、私に起こったら、あなたに返信します。

具体的なクラスを使用することをお勧めします。
すなわち代わりに

*new {* 

やったときに参加し、常に我々はLINQの内部で何が起こっているかをうまくまで、それは少し長いですが、少なくとも...より安全に、より安全な

*new CLASSNAME(){prop1="abc",prop2="123"* 

を使用内部。

+0

これは役に立ちます。しかし、私はどのようにしてBの他のメンバー(あなたの例ではO)を得ることができますか?この例では、キーの組み合わせに最小型を加えたものだけを取得しますが、他のメンバーをどのように取得しますか? –

+0

私は*「SELECT TOP 1 ... ORDER BY ...」がやっていたと思っていました。あなたは他のどのメンバーが欲しいのですか? – sgtz

+0

申し訳ありませんが、よく見えませんでした。あなたのソリューションは大丈夫です! –

0

を有意義にするために参加するには、[*、A.だけでなく、結果を照会するには、少なくとも何かを追加する必要があります。さもなければ、おそらく複製されたいくつかの行を持つAのコピーがあります。

SELECT DISTINCT A.*, B.Type 
FROM A LEFT JOIN 
(SELECT TOP (1) JoinID, Type 
FROM B 
ORDER BY Type 
GROUP BY JoinID, Type 
) AS B ON A.JoinID = B.JoinID 

LINQに翻訳、それは(UPDATED

(from a in As 
join b in 
(from b1 in Bs 
orderby b1.Type 
group b1 by b1.JoinID into B1 
from b11 in B1 
group b11 by b11.Type into B11 
from b111 in B11 
select new { b111.JoinID, b111.Type }).Take(1) 
on a.JoinID equals b.JoinID into a_b 
from ab in a_b.DefaultIfEmpty()    
select new { a_b.JoinID, /*all other a properties*/ a_b.Type }).Distinct() 

LINQは100%正しい動作しない場合がありますが、あなたはつかむ必要があります:私が正しく質問を理解している場合、このSQLクエリは動作するはずですアイデア。

+0

これは、私が探しているものではない複数の組み合わせAとBをもたらします。 1つのレコードAと1つ(またはゼロ)のレコードBが必要です。 –

+0

@Stefan私はTOP 1を忘れました。修正されました。 –

関連する問題