2009-05-07 10 views
2

次のクエリをLINQに変換する方法について午後に取り組んできましたが、私はそこに到達できません。LINQを使用したサブクエリでの高度な複数の結合

declare @productId int; set @productId = 3212; 

select * from InformationData data where productId = @productId and orgId = 1 
and exists(
    select id from (
     select coalesce(id1.id, id2.id, id3.id) as id from (
      select productId,attributeId from InformationData where productId = @productId group by productId,attributeId 
     ) id 
     left outer join InformationData id1 on id1.productId = id.productId and id1.attributeId = id.attributeId and id1.language = 1 
     left outer join InformationData id2 on id2.productId = id.productId and id2.attributeId = id.attributeId and id2.language = 2 
     left outer join InformationData id3 on id3.productId = id.productId and id3.attributeId = id.attributeId and id3.language = 0 
    ) row 
    where row.id = data.id 
) 

クエリの目的は、2つのフォールバック言語を使用してテーブルからデータを取得するデータは、言語1に存在しないので、もし、それが言語2に取り込まれ、そして2が存在しない場合、それはグローバルな翻訳である言語0を取得します。

私はほとんど正しいの内側のクエリを取得することができます(id1.language = 1から、私はそれは私がすべてのアイデア、に参加していますテーブルのメンバーに参加してもらうように見えることはできませんを除く?)

これは私のコード(LINQPadコード)である:

次のSQL生成
(
    from data in (
     from d in InformationData where d.ProductId == 3212 group d by new { d.ProductId, d.AttributeId } into p select new { ProductId = p.Key.ProductId, AttributeId = p.Key.AttributeId } 
    ) 
    join x1 in InformationData on new { a = data.ProductId, b = data.AttributeId } equals new { a = x1.ProductId, b = x1.AttributeId } into f1 
     from r1 in f1.DefaultIfEmpty() 
     where r1.Language == 1 
    join x2 in InformationData on new { a = data.ProductId, b = data.AttributeId } equals new { a = x2.ProductId, b = x2.AttributeId } into f2 
     from r2 in f2.DefaultIfEmpty() 
     where r2.Language == 2 
    join x3 in InformationData on new { a = data.ProductId, b = data.AttributeId } equals new { a = x3.ProductId, b = x3.AttributeId } into f3 
     from r3 in f3.DefaultIfEmpty() 
     where r3.Language == 2 
    select new { Id = ((int?)r1.Id) ?? ((int?)r2.Id) ?? r3.Id } 
).Dump(); 

-- Region Parameters 
DECLARE @p0 Int SET @p0 = 3212 
DECLARE @p1 Int SET @p1 = 2 
DECLARE @p2 Int SET @p2 = 2 
DECLARE @p3 Int SET @p3 = 1 
-- EndRegion 
SELECT COALESCE([t2].[id],COALESCE([t3].[id],[t4].[id])) AS [Id] 
FROM (
    SELECT [t0].[productId], [t0].[attributeId] 
    FROM [InformationData] AS [t0] 
    WHERE [t0].[productId] = @p0 
    GROUP BY [t0].[productId], [t0].[attributeId] 
    ) AS [t1] 
LEFT OUTER JOIN [InformationData] AS [t2] ON ([t1].[productId] = [t2].[productId]) AND ([t1].[attributeId] = [t2].[attributeId]) 
LEFT OUTER JOIN [InformationData] AS [t3] ON ([t1].[productId] = [t3].[productId]) AND ([t1].[attributeId] = [t3].[attributeId]) 
LEFT OUTER JOIN [InformationData] AS [t4] ON ([t1].[productId] = [t4].[productId]) AND ([t1].[attributeId] = [t4].[attributeId]) 
WHERE ([t4].[language] = @p1) AND ([t3].[language] = @p2) AND ([t2].[language] = @p3) 

をしかし、私は多分私はちょうどよ、クエリの残りの部分と一緒にこれを置くことができません疲れた私は私を得ることを続けるCROSS APPLYをたくさんしています。誰にも何か提案はありますか?

答えて

3

をし、いくつかのクランチングものが少し明るくなったと私が見つかりました:たとえば、優先順位は何か、その後、その後、その後、2、3、1であるべきならば、あなたはこれを行うことができます> - それは


(
    from i in InformationData 
    where (
     from data in (
      from d in InformationData where d.ProductId == 3212 group d by new { d.ProductId, d.AttributeId } into p select new { ProductId = p.Key.ProductId, AttributeId = p.Key.AttributeId } 
     ) 
     join x1 in InformationData on new { a = data.ProductId, b = data.AttributeId, c = 1} equals new { a = x1.ProductId, b = x1.AttributeId, c = x1.Language } into f1 
      from r1 in f1.DefaultIfEmpty() 
     join x2 in InformationData on new { a = data.ProductId, b = data.AttributeId, c = 2 } equals new { a = x2.ProductId, b = x2.AttributeId, c = x2.Language } into f2 
      from r2 in f2.DefaultIfEmpty() 
     join x3 in InformationData on new { a = data.ProductId, b = data.AttributeId, c = 0 } equals new { a = x3.ProductId, b = x3.AttributeId, c = x3.Language } into f3 
      from r3 in f3.DefaultIfEmpty() 
     select new { Id = ((int?)r1.Id) ?? ((int?)r2.Id) ?? r3.Id } 
    ).Any(d => d.Id == i.Id) 
    select i 
).Dump(); 

そして、ここで、ここで好奇心旺盛で、誰のためのソリューションは:)生成されたSQL


-- Region Parameters 
DECLARE @p0 Int SET @p0 = 3212 
DECLARE @p1 Int SET @p1 = 1 
DECLARE @p2 Int SET @p2 = 2 
DECLARE @p3 Int SET @p3 = 0 
-- EndRegion 
SELECT [t0].[id] AS [Id], [t0].[attributeId] AS [AttributeId], [t0].[productId] AS [ProductId], [t0].[value] AS [Value], [t0].[orgId] AS [OrgId], [t0].[version] AS [Version], [t0].[language] AS [Language], [t0].[metaType] AS [MetaType], [t0].[overload] AS [Overload], [t0].[parentId] AS [ParentId] 
FROM [InformationData] AS [t0] 
WHERE EXISTS(
    SELECT NULL AS [EMPTY] 
    FROM (
     SELECT COALESCE([t3].[id],COALESCE([t4].[id],[t5].[id])) AS [value] 
     FROM (
      SELECT [t1].[productId], [t1].[attributeId] 
      FROM [InformationData] AS [t1] 
      WHERE [t1].[productId] = @p0 
      GROUP BY [t1].[productId], [t1].[attributeId] 
      ) AS [t2] 
     LEFT OUTER JOIN [InformationData] AS [t3] ON ([t2].[productId] = [t3].[productId]) AND ([t2].[attributeId] = [t3].[attributeId]) AND (@p1 = [t3].[language]) 
     LEFT OUTER JOIN [InformationData] AS [t4] ON ([t2].[productId] = [t4].[productId]) AND ([t2].[attributeId] = [t4].[attributeId]) AND (@p2 = [t4].[language]) 
     LEFT OUTER JOIN [InformationData] AS [t5] ON ([t2].[productId] = [t5].[productId]) AND ([t2].[attributeId] = [t5].[attributeId]) AND (@p3 = [t5].[language]) 
     ) AS [t6] 
    WHERE [t6].[value] = [t0].[id] 
    ) 
2

ほとんどの場合、クエリの実行内容に関する説明に基づいて、適切な「orderby」句を使用して同じ結果を達成し、最初の結果のみを取得できる可能性があります。このように:

var result = 
(
    from d in InformationData 
    where d.ProductId == 3212 
    orderby ((d.language == 0) ? Int32.MaxValue : d.language) 
    select d 
).First(); 

EDIT:あなたはORDERBY句を拡張することで、検索の優先順位を制御することができます。良い睡眠をよくした後

var result = 
(
    from d in InformationData 
    where d.ProductId == 3212 
    orderby 
     (d.language == 2) ? 0 
     : (d.language == 3) ? 1 
     : (d.language == 1) ? 2 
     : Int32.MaxValue 
    select d 
).First(); 
+0

は、残念ながら、それは私が1からフォールバックする必要があるケースを持つことができるように、この単純ではありませんさ2→0または3→2→0となる。昇順または降順に並べ替えるには、条件に基づいてソートを作成することがありますが、私は試してみましょう。私はこれを解決する方法についてはまだ非常に興味があります。なぜなら、私はかなり複雑なアプリケーションをたくさんのクエリで翻訳しているからです。 – Runeborg

+0

より複雑な優先順位/フォールバックシーケンスの例を追加しました。 –

+0

良い提案、私はこれを試してみます。現在私は多くの待ち時間のためにそれをプロファイルすることはできません。 – Runeborg

関連する問題