

列が30個くらいあるテーブルがあると仮定して、レコードは膨大に日々増えるとします。  
列は30個を当初固定しますが、35個等に増やす可能性があります。

AAA,BBB,FFF

AAA,CCC,DDD

BBB,CCC,EEE

というようなデータが入っている場合、

AAAが組み合わせにある他の関連するデータを探すために、入力フォームに入力すると、  
BBB,CCC,DDD,FFF  
が関連するデータとして表示され、

CCCが組み合わせにある他の関連するデータを探すために、入力フォームに入力すると、  
AAA,BBB,DDD,EEEが  
関連するデータとして表示される

という仕組みを作る場合は、  
データの保存、検索の考え方、  
RDBでのテーブルの設計の考え方は、  
どのようにするのが定石でしょうか？

よろしくお願いいたします。


CC BY-SA 3.0
2015-10-28T02:29:18.757
18154
2015-10-31T11:43:23.403
2015-10-28T11:05:07.013
12907
12907
question
sql database
組み合わせでの関連するデータを管理する方法


質問の意図を取り違えているかもしれませんが、  
連想元(例えば'AAA')と連想先(例えば'BBB', 'CCC', 'DDD', 'FFF')の関係を関連テーブルで表すのはどうでしょうか。  
以下、関連の方向は単方向(AAAの関連データにBBBが存在する場合でも、必ずしもBBBの関連データにAAAが存在するとは限らない)として記載しています。  
(双方向の場合は、associationの登録時に少し考慮が必要になります(`key_content_id`の値と`value_content_id`の値が逆になっているだけのレコード登録を拒否する必要がある)。)

[![ER図](https://i.stack.imgur.com/iJ8Q2.png)](https://i.stack.imgur.com/iJ8Q2.png)

content:

[code]

    +----+------+
    | id | data |
    +----+------+
    |  1 | AAA  |
    |  2 | BBB  |
    |  3 | CCC  |
    |  4 | DDD  |
    |  5 | EEE  |
    |  6 | FFF  |
    +----+------+
    
[/code]

association(の一部):

[code]

    +----+----------------+------------------+
    | id | key_content_id | value_content_id |
    +----+----------------+------------------+
    |  1 |              1 |                2 |
    |  2 |              1 |                3 |
    |  3 |              1 |                4 |
    |  4 |              1 |                6 |
    |  5 |              3 |                1 |
    |  6 |              3 |                2 |
    |  7 |              3 |                4 |
    |  8 |              3 |                5 |
    +----+----------------+------------------+
    
[/code]

* * *

contentに新しく以下のレコードを登録する場合、

[code]

    +----+------+
    | id | data |
    +----+------+
    |  7 | GGG  |
    +----+------+
    
[/code]

例えば'AAA'の連想先に'GGG'があり、'GGG'の連想先に'BBB','CCC'があるのであれば、associationテーブルに新しく登録すべきデータは以下のようになります。

[code]

    +----+----------------+------------------+
    | id | key_content_id | value_content_id |
    +----+----------------+------------------+
    |  9 |              1 |                7 |
    | 10 |              7 |                3 |
    | 11 |              7 |                3 |
    +----+----------------+------------------+
    
[/code]

関連をたどれば連想元から連想先を引いてくることができます。  
SQL:

[code]

    select v.data from content v where id in (
        select value_content_id from association 
        inner join (
            select id from content where data = 'AAA'
        ) k
        on association.key_content_id = k.id
    );
    
[/code]

`k`(keyの意),
`v`(valueの意)は、`FROM`句に登場させているcontentテーブルの[別名](https://technet.microsoft.com/ja-
jp/library/ms187455\(v=sql.105\).aspx)です。文中、異なる意味で2回(連想元として、連想先として)出てきていますので、区別がつくように別の名前をつけています。

実際にやりたいことを図で表してみると以下のようになると思います。

[![処理概念](https://i.stack.imgur.com/3T9UN.png)](https://i.stack.imgur.com/3T9UN.png)

これを文章で表すと次の手順で所望のデータを取得する、ということになります。

  1. associationに登録された関連を取得するためにcontentから'AAA'のIDを取得する
  2. 取得したIDを用い、'AAA'の連想先IDをassociationから実際に取得する
  3. 取得した連想先IDを用いcontentから連想先の実体を取得する

以下、それぞれについて見ていきます。

### associationに登録された関連を取得するためにcontentから'AAA'のIDを取得する

前述のSQLのうち、以下の部分が該当します。

[code]

    select id from content where data = 'AAA'
    
[/code]

実際にはこれに別名`k`をつけていますので、次のようなテーブルができたと考えてください。

[![kテーブル](https://i.stack.imgur.com/mrJ1V.png)](https://i.stack.imgur.com/mrJ1V.png)

`id`というカラムを持ち、レコード数が1のテーブルです。

### 取得したIDを用い、'AAA'の連想先IDをassociationから取得する

前述のSQLのうち、次の部分が該当します。

[code]

    select value_content_id from association 
    inner join k
    on association.key_content_id = k.id
    
[/code]

`association` と `k` を inner join したテーブルは以下のようなものになります。

[![assosiationとkのjoin
table](https://i.stack.imgur.com/DPbjh.png)](https://i.stack.imgur.com/DPbjh.png)

'AAA'のID`1`を`key_content_id`に持つレコードのみが存在します。  
すなわち、このテーブルの`value_content_id`が'AAA'の連想先IDということになります。

### 取得した連想先IDを用いcontentから連想先の実体を取得する

[code]

    select v.data from content v where id in (2,3,4,6)
    
[/code]

`content`から指定した`id`の`data`を取得します。これが連想先です。


CC BY-SA 3.0
2015-10-28T05:08:09.673
18158
2015-10-31T11:43:23.403
2015-10-31T11:43:23.403
2808
2808
18154
answer