2017-01-11 9 views
1

私は、ユーザーがワークフローの一環として「コンポーネント」にタグを付けることができるアプリケーションに取り組んでいます。多くの場合、それらはお互いの同義語であるいくつかのタグで終わる。彼らは、これらをグループ化して、1つのタグがコンポーネントに追加されたときに、そのグループの残りのタグも追加できるようにします。双方向関係のテーブルを別々のグループに分割する

タググループをグループ内の各タグペア間の双方向関係に分割することに決めました。

ID  TagID RelatedTagID 
1  1  2 
2  2  1 

基本的には、グループは、その中に各タグのデカルト積として表される:グループは、タグ1と2を持っているのであれば、このようになりますレコードがあります。 3つのタグにそれを拡張:

ID Name 
1  MM 
2  Managed Maintenance 
3  MSP 

私たちの関係は次のようになります。

ID TagID RelatedTagID 
1  1  2 
2  2  1 
3  1  3 
4  3  1 
5  2  3 
6  3  2 

私はグループ一緒にカップルのメソッドを持っていますが、彼らは恒星未満です。まず、私は、そのグループ内のタグのリストとともに、各タグを一覧表示ビューを書いた:

SELECT 
    TagKey AS ID, 
    STUFF 
     ((SELECT ',' + cast(RelatedTagKey AS nvarchar) 
      FROM RelatedTags rt 
      WHERE rt.TagKey = t.TagKey 
      FOR XML PATH('')), 1, 1, '') AS RelatedTagKeys 
FROM (
    SELECT DISTINCT TagKey 
    FROM RelatedTags 
) t 

これに伴う問題は、その中にタグがあるとして、各グループが、結果に何度でも表示されていることです私は単一のクエリで対処する方法を考えることができませんでした。だから、私に戻っています:

ID RelatedTagKeys 
1  2,3 
2  1,3 
3  1,2 

はその後、私のバックエンドでは、私は別のグループで発生するキーが含まれているすべてのグループを破棄する。タグは複数のグループに追加されているわけではありませんが、そのように機能していますが、無関係なデータがどれくらい残っているのが好きではありません。

私が思い描いた2番目の解決策は、このLINQクエリでした。タグをグループ化するために使用されるキーは、グループ自体のリストです。これはおそらく私が元々考えていたよりもはるかに悪いでしょう。

from t in Tags.ToList() 
where t.RelatedTags.Any() 
group t by 
    string.Join(",", (new List<int> { t.ID }) 
     .Concat(t.RelatedTags.Select(i => i.Tag.ID)) 
     .OrderBy(i => i)) 
into g 
select g.ToList() 

私は本当にstring.Joinを呼び出した結果によってグループ化する嫌いが、私はちょうどキーのリストによってグループ化しようとしたとき、それは自分自身でグループ内の各タグを入れて、適切にグループではありませんでした。また、生成されたSQLはモンスターです。私はここに貼りつけるつもりはありませんが、LINQPadは、私のテストデータベース上に約12,000行の個別SELECT文を生成することを示しています(関連タグには1562個のタグと67個のレコードがあります)。

これらのソリューションは機能しますが、かなり単純で非効率的です。私はこれと一緒にどこに行くのか分からない。何か案は?

+0

期待される結果は何ですか?あなたの質問からはそれほど明確ではありません。 – wdosanjos

+0

申し訳ありませんが、私は恐れていたことが起こるかもしれません。私の例には1つのグループがあり、期待される結果はそのグループを関係のリストから派生させることです。もちろん、それは複数のグループでうまくいくはずですが、私の質問はもっと冗長になります。 –

答えて

1

私はあなたが関連しているタグがgroupIdの同じ値を共有するようにあなたのタグのそれぞれについてgroupIdを、持っている場合は、あなたのデータでの作業は容易になるとします。私が何を意味するか説明するために 、私はあなたのデータセットに関連するタグの第2のセットを追加しました:

INSERT INTO tags ([ID], [Name]) VALUES 
    (1, 'MM'), 
    (2, 'Managed Maintenance'), 
    (3, 'MSP'), 
    (4, 'UM'), 
    (5, 'Unmanaged Maintenance'); 

INSERT INTO relatedTags ([ID], [TagID], [RelatedTagID]) VALUES 
    (1, 1, 2), 
    (2, 2, 1), 
    (3, 1, 3), 
    (4, 3, 1), 
    (5, 2, 3), 
    (6, 3, 2), 
    (7, 4, 5), 
    (8, 5, 4); 

を次に、以下の情報を保持しているテーブルは、他の多くのことを容易にすべきです(私は、最初のクエリを使用して、それを取得する方法を、テーブルの内容を説明し、):

tagId | groupId 
------|-------- 
1  | 1 
2  | 1 
3  | 1 
4  | 4 
5  | 4 

データ、すなわち、関連するタグの2つのグループを含み、{1,2,3}および{4,5}。したがって、上記の表は、同じグループに属するタグをgroupIdと表示します。1{1,2,3}4{4,5}です。

は、このようなビュー/テーブルを達成するには、次のクエリを使用できます。もちろん

with rt as 
((select r2.tagId, r2.relatedTagId 
    from relatedTags r1 join relatedTags r2 on r1.tagId = r2.relatedTagId) 
union 
    (select r3.tagId, r3.tagId as relatedTagId from relatedTags r3) 
) 
select rt.tagId, min(rt.relatedTagId) as groupId from rt 
group by tagId 

、代わりに新しいテーブル/ビューを導入するのを、あなたもgroupIdによってプライマリ-table tagsを拡張することができ属性。

これが役に立ちます。

+0

それははるかに良い解決策です。私はちょうど悪いデザインであまりにも賢いようにしようとしたと思う。 –

0

私は本当に関係を理解し​​ていません。あなたはとてもうまく説明しなかった。しかし、私は何とか同じ結果を得ました。私がそれを正しかったかどうかは分かりません。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 


namespace ConsoleApplication41 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Data.data = new List<Data>() { 
       new Data() { ID = 1, TagID = 1, RelatedTagID = 2}, 
       new Data() { ID = 2, TagID = 2, RelatedTagID = 1}, 
       new Data() { ID = 3, TagID = 1, RelatedTagID = 3}, 
       new Data() { ID = 4, TagID = 3, RelatedTagID = 1}, 
       new Data() { ID = 5, TagID = 2, RelatedTagID = 3}, 
       new Data() { ID = 6, TagID = 3, RelatedTagID = 2} 
      }; 

      var results = Data.data.GroupBy(x => x.RelatedTagID) 
       .OrderBy(x => x.Key) 
       .Select(x => new { 
        ID = x.Key, 
        RelatedTagKeys = x.Select(y => y.TagID).ToList() 
       }).ToList(); 

      foreach (var result in results) 
      { 
       Console.WriteLine("ID = '{0}', RelatedTagKeys = '{1}'", result.ID, string.Join(",",result.RelatedTagKeys.Select(x => x.ToString()))); 
      } 
      Console.ReadLine(); 

     } 
    } 
    public class Data 
    { 
     public static List<Data> data { get; set; } 
     public int ID { get; set; } 
     public int TagID { get; set; } 
     public int RelatedTagID { get; set; } 

    } 
} 
関連する問題