2003年10月 1日 複合 キー (その 2) >> 目次 (テーマ ごと)
  ● QUESTION   ひとつの認知番号が複合 キーになっているが、どのように扱えばよいか。
  ▼ ANSWER   まず、(複合 キーのまま)認知番号を使って作図して、作図後に検討すればよい。
2008年10月16日 補遺  



 1 つの認知番号が、複数の項目から構成されていることが多い。
 そういう コード 体系は、1970 年代の コード 体系である。すなわち、データ に アクセス する テクニック として、キー と レコード という技術 (レコード・アット・ア・タイム) しかなかった時代において、データ に対する アクセス を効率化するために導入されていた テクニック である。

 そういう コード 体系の典型的な例として、たとえば、品目番号が 34桁であって、最初の 2桁が 「製品・半製品」 を示す コード であったとする。そして、事業が拡大するにつれて、対象品目が 100種類を超えたとすれば、キー として固定されている 2桁──「99」 まで扱うことができるが──に対して、データ の並びを崩さないために、「A1」 という値を使わざるを得ない。だが、「A1」 という コード は、いったい、エンドユーザ にとって、どういう意味があるのか。

 認知番号は、原則として、(「桁溢れ」 しないような) 無意味な連番であるほうがよい。
 ただ、データ を使う エンドユーザ にしてみれば、認知番号の値を一目観れば、データ の中味が直ぐに判断できるほうが仕事をしやすい、と考えるのは当然である。たとえば、商品番号として、「0001」 と記述されているよりも、(シリーズ T のなかで、2003 年に製造された、オプション A を装備したことを示すために)「T03-OPA」 としたほうが、商品の中味を直ぐに判断することができる。

 したがって、今後も、複合 キー の考えかたは、根強く遺ると思われる。
 ただし、コード 体系を変更したほうが良いと判断される (いくつかの) コード について、DA (Data Analyst) は、問題点と改善案を エンドユーザ に提言したほうがよい。

 
事業の前提

 以下を前提とする。

  (1) 商品を中継ぎする仕事 (コーディネータ) をしている。
  (2) 営業部がある (認知番号は営業部 コード)。
  (3) 取引先には、以下の 2つがある。
      - 受注先 (認知番号は受注先 コード)
      - 注文先 (認知番号は注文先 コード)
  (4) 受注先かつ注文先はない。
  (5) 営業部は受注先から受注して、注文先に注文する。
  (6) 受注番号は複合 キー である。 (営業部+年度+連番)
  (7) 注文番号は複合 キー である。 (営業部+年度+連番)
  (8) 受注と注文の関係は 「1-対-複数」 である。
  (9) 受注する営業部と注文する営業部は、それぞれ、相違する営業部である。

 
データ 構造

 事業を記述する基本的な データ 構造は、以下のようになる。

   営業部
   { 営業部 コード、営業部名称、・・・ } [ R ]

   受注先
   { 受注先 コード、受注先名称、・・・ } [ R ]

   注文先
   { 注文先 コード、注文先名称、・・・ } [ R ]

   受注
   { 受注番号、受注先 コード (R)、営業部 コード (R)、受注日、受注数、・・・ } [ E ]

   注文
   { 注文番号、注文先 コード (R)、営業部 コード (R)、受注番号(R)、注文日、注文数、・・・ } [ E ]

 
データ 構造の検討 (その 1)

 さて、T字形 ER手法の ルール どおりに記述した (前述した) データ 構造では、以下の点が論点となる。

  (1) 1 つの受注 データ のなかで、同じ値の営業部 コード が 2つある。
  (2) 1 つの注文 データ のなかで、同じ値の営業部 コード が 2つある。

 そうなった原因は、受注番号および注文番号が、それぞれ、複合 キー になっていて、(複合 キー が) 営業部 コード をなかにふくんでもっているからである。
 それを正すために、まず、データ 構造を以下のように修正する。

   営業部
   { 営業部 コード、営業部名称、・・・ } [ R ]

   受注先
   { 受注先 コード、受注先名称、・・・ } [ R ]

   注文先
   { 注文先 コード、注文先名称、・・・ } [ R ]

   営業部. 受注先. 対照表 (「受注」 を示す)
   { 営業部 コード (R)、受注先 コード (R)、受注日、受注数、連番、・・・ } [ 対照表 ]

   営業部. 注文先. 対照表 (「注文」 を示す)
   { 営業部 コード (R)、注文先 コード (R)、注文日、注文数、連番、・・・ } [ 対照表 ]

   営業部. 受注先. 注文先. 対照表 (「受注」 と 「注文」 の対応を示す)
   { 営業部 コード (R)、受注先 コード (R)、営業部コード(R)、注文先 コード (R)、・・・ } [ 対照表 ]

 
 ただし、この構造では、受注および注文は、受注先および注文先という アカウント 制のなかで トータル として把握できるが、トランザクション 単位の対応ができない。

 
データ 構造の検討 (その 2)

 そこで、次ぎに、(複合 キー がふくんでもっていた 「連番」 に着目して) データ 構造を、以下のように修正する。

   営業部
   { 営業部 コード、営業部名称、・・・ } [ R ]

   受注先
   { 受注先 コード、受注先名称、・・・ } [ R ]

   注文先
   { 注文先 コード、注文先名称、・・・ } [ R ]

   受注
   { 連番 (受注番号)、受注先 コード (R)、営業部 コード (R)、受注日、受注数、・・・ } [ E ]

   注文
   { 連番 (注文番号)、注文先 コード (R)、営業部 コード (R)、連番 (R) [受注番号 (R) ]、注文日、注文数、・・・ } [ E ]

 
 以上の構造から判断できる点は、それぞれの 「連番」 が、受注番号および注文番号であればよいのであって、受注番号および注文番号を複合 キー にする意味がない、ということである。言い換えれば、複合 キー のなかにふくまれていた受注番号および注文番号は、計算の集計に使われる キー にすぎない。

 T字形 ER手法では、「まず、技術 (ルール) どおりに」 記述すれば、コード の矛盾が露呈されるしくみになっている。そして、問題点が炙りだされたなら、改善案を考えればよい。DA は、以上の検討のなかで認識した コード 体系の変更を エンドユーザ に提言すればよい。

 なお、最終的な データ 構造は、以下のように、「概念的な スーパーセット」 を記述しておけば、もっと、事業を理解しやすい記述になる。

   営業部
   { 営業部 コード、営業部名称、・・・ } [ R ]

   取引先[ 概念的 スーパーセット ]
    |
    ×
    │
    ├受注先 { 受注先 コード、受注先名称、・・・ } [ R ]
    │
    └注文先 { 注文先 コード、注文先名称、・・・ } [ R ]

   受注
   { 連番 (受注番号)、受注先 コード (R)、営業部 コード (R)、受注日、受注数、・・・ } [ E ]

   注文
   { 連番 (注文番号)、注文先 コード (R)、営業部 コード (R)、連番 (R) [ 受注番号 (R) ]、注文日、注文数、・・・ } [ E ]

 



[ 補遺 ] (2008年10月16日)

 本文の記述に関して、ひとつの補足説明と ひとつの訂正をします。

 まず、補足説明のほうですが、「製品・半製品」 区分 について、2 桁を超える事態が起こったら、キー に限らず、データ 項目そのもの-の桁数を修正しなければならないので、キー 構成のなかに 「製品・半製品」 区分が使われていること そのもの-の非難にはならないのではないか という意見がありますが、私が争点にしたいのは、キー として定義された物が、いったい、どういう 「事実」 を指示しているのか という点です。キー は、あくまで、アクセス の効率を狙って使われる物であって、一意性を満たす必要十分条件は 「個体そのものが一意であればいい」 という点でしょう。すなわち、RDB の構成で言えば、row の値の総体が一意であればいいということです。一意的な キー (unique-key) を使って、データ (個体) の存在を確認してから、必要な データ 項目を view で入手するというのは、逆に非効率でしょう。たとえば、{ a, b, c } という構成において、{ a, b } を複合 キー として、{ a, b } の或る値に対応する { c } を入手したいのであれば、最初から { a, b, c } という view (あるいは、index-key) で アクセス すればいい、ということです。

 次に、訂正点のほうですが、文中で 「認知番号は、原則として、(「桁溢れ」 しないような) 無意味な連番であるほうがよい」 と綴っていますが、私は、「無意味な連番」 を推奨している訳ではないので、説明が足らなかったと反省しています。個体指定子 (entity-setter) は、個体を 「なんらかの順に並べる」 関数的な役割です──ただし、個体の並びは 「全順序」 になっていなくてもいい。ここでいう 「全順序」 とは、大小とか時系列というふうな 「線型順序」 のことをいいます。たとえば、「商品」 entity の個体指定子として、かならずしも 「商品番号 (しかも、製造された日付順に並ぶように数を割り当てられた番号)」 でなくて、以下のように、「商品略称名」 でもいい。たとえば、もし、商品が 「ネジ」 などであれば、個々の個体に一つずつ番号を付与するのは逆に非効率でしょう──つまり、個体ひとつずつに対して個体指定子を付与することは無意味でしょうし、そのときには、「(個体を いくつか まとめた) ロット」 に対して番号を付与するかもしれない。

   { 商品略称名、商品名称、・・・ }.

 基本的には、個体指定子は、事態のなかに関与する個体を一意に指示する なんらかの記号──ただし、データ 部の意味をふくまないような記号──であればいいということです。個体そのものは現実的に一意で存在しても、個体の使われかたは 「事態」 のなかで指示されるということです。この点が、個体指定子の値を考えるときに難しい点になっている理由ですし、個体指定子そのものが、かなずしも一意にならない理由です。たとえば、以下を考えてみてください。

 (1) 営業所ごとに契約を管理している。
 (2) 営業所 コード で 「営業所」 entity が認知されている。
 (3) 契約番号で 「契約」 entity が認知されている。
 (4) それぞれの営業所は、管理下の契約番号に対して、それぞれ連番を付与している。

 とすれば、以下の構成において、契約番号 (個体指定子) そのものは一意にならないでしょう。

   { 契約番号、営業所 コード (R)、契約日、・・・ }.

 でも、それぞれの契約は、一意に存在しています。
 そして、この データ を、もし、営業所のなかで扱うのであれば、契約番号は一意ですが、複数・多数の営業所のあいだで扱うのであれば、データ の一意性は 「営業所 コード + 契約番号」 の複合構成でなければならないでしょう。そして、もし、「営業所 コード + 契約番号」 を キー (unique-key) にすれば、それぞれの営業所では無意味でしょうね。つまり、個体指定子の値は、それぞれの文脈 (適用区域) のなかで決まるのであって、かならずしも、個体の一意的存在そのもので決まる訳ではないという点に注意していて下さい。





  << もどる HOME すすむ >>
  データ解析に関するFAQ