<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>候補キー &#8211; SRA OSS Tech Blog</title>
	<atom:link href="https://www.sraoss.co.jp/tech-blog/tag/f061ddf2bf81d41e49ab0d181623c311/feed/index.xml" rel="self" type="application/rss+xml" />
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<description>OSS専門の技術ブログ。PostgreSQL、Zabbixを中心に10種類以上のOSSの解説、アップデート情報、運用ヒントを提供。</description>
	<lastBuildDate>Wed, 04 Nov 2026 06:39:59 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2018/07/blog-icon-150x150.png</url>
	<title>候補キー &#8211; SRA OSS Tech Blog</title>
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>増永教授のDB特論④「候補キーの見つけ方」</title>
		<link>https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-4/</link>
		
		<dc:creator><![CDATA[増永良文 (Yoshifumi Masunaga)]]></dc:creator>
		<pubDate>Wed, 06 Apr 2022 00:00:59 +0000</pubDate>
				<category><![CDATA[増永教授のDB特論]]></category>
		<category><![CDATA[RDB]]></category>
		<category><![CDATA[リレーショナルデータベース]]></category>
		<category><![CDATA[候補キー]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=9482</guid>

					<description><![CDATA[1. はじめに &#8195;SQL でテーブルを定義するときに PRIMARY KEY や UNIQUE を指定すると思いますが，皆さんはリレーション（スキーマ）のキー（key）を一体どのようにして見つけていますか？ &#038; ...]]></description>
										<content:encoded><![CDATA[<h4>1. はじめに</h4>
<p style="margin-top: -10px;">
&emsp;SQL でテーブルを定義するときに PRIMARY KEY や UNIQUE を指定すると思いますが，皆さんはリレーション（スキーマ）のキー（key）を一体どのようにして見つけていますか？<br />
&emsp;そもそも，「キーとはタップルの一意識別能力を有する属性の<ruby>極<rt style="background-color: #DDDDDD;">・</rt></ruby><ruby>小<rt style="background-color: #DDDDDD;">・</rt></ruby>組」であることは，リレーショナルデータモデルを学んだ人ならばデータベースのイロハといった事項でしょうが，具体的にリレーション（スキーマ）と所与の関数従属性の集合が指定されたときに，キーを求めなさいと言われると，結構難儀する場合もあるのではないか，と思います．<br />
&emsp;本稿では，次に示す 3 つの問題について改めて論じてみます．</p>
<ul style="margin-top: -08px;">
<li style="margin-top: -25px; margin-left: +50px;">候補キーを 1 つ見つける．</li>
<li style="margin-left: +50px;">候補キーをすべて見つける．</li>
<li style="margin-left: +50px;">候補キーの数の上限は？</li>
</ul>
<p><span id="more-9482"></span></p>
<h4>2. 基礎的事項</h4>
<p style="margin-top: -10px;">
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> とはリレーション名 R と属性のリスト A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub> からなり，<b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>)と表されます．Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> (= { A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub> })で <b><span style="font-style: italic;">R</span></b> の全属性集合を表すことにします．<b><span style="font-style: italic;">R</span></b> をリレーションスキーマとするとき，<b><span style="font-style: italic;">R</span></b> に所与の（given）関数従属性の集合 <span style="font-style: italic;">F</span>＝{f<sub>1</sub>, f<sub>2</sub>, <sub>…</sub>, f<sub>p</sub>}，ここに (∀<sub>i</sub>= 1, 2, <sub>…</sub>, p)(f<sub>i</sub>=X<sub>i</sub>→Y<sub>i</sub> ∧ X<sub>i</sub>, Y<sub>i</sub>⊆Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>)，を指定できます．なお，一般に X, Y を集合とするとき，X⊆Y は X が Y の部分集合であることを，X⊂Y は X が Y の真部分集合（proper subset）であることを表します．</p>
<p><strong>【定義 1】</strong>（候補キー）<br />
&emsp;K⊆Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> がリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の<strong>候補キー</strong>（candidate key）と言われるのは，次が成立するときをいう．ここに，∀R∈<b><span style="font-style: italic;">R</span></b> は「<b><span style="font-style: italic;">R</span></b> の任意のインスタンス R に対して」を表す．</p>
<p style="margin-top: -25px; margin-left: +50px;">(∀R∈<b><span style="font-style: italic;">R</span></b>)((∀t, t’∈R)(t[K]=t’[K] ⇒ t=t’) ∧</p>
<p style="margin-top: -25px; margin-left: +50px;">(∀H⊂K)(∃R∈<b><span style="font-style: italic;">R</span></b>) ((∃t, t’∈R)(t[H]=t’[H] ∧ t≠t’)))</p>
<p>&emsp;リレーションは有限個のドメインの直積の有限部分集合と定義されているので ，いかなるリレーションにも候補キーがないということはなく，最も極端なケースはリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の全属性集合 Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> が候補キーとなることも皆さんにとっては常識でしょう．<br />
&emsp;組織体管理者（enterprise administrator, すなわち組織のデータベース設計に責任を有する個人またはグループ）は，候補キーが一つしかなければそれを，複数ある場合にはデータベース構築の目的に合っていると考えられるものを一つを選んで<strong>主キー</strong>（primary key）とします．主キーとされなかった候補キーと主キーとの違いは，主キーには<strong>キー制約</strong>（key constraint）が課せられることにあることもよくご存じのことでしょう．また，何らかの候補キーを含む属性集合を<strong>スーパーキー</strong>（super key）と言います．</p>
<p><strong>【定義 2】</strong>（キー制約）<br />
&emsp;K がリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の主キーであるならば，次が成立しなければならない．ここに，NULLは空（すなわち，値がないこと）を表す．</p>
<p style="margin-top: -25px; margin-left: +50px;">(∀R∈<b><span style="font-style: italic;">R</span></b>) (∀t∈R)((∀A∈K)(t[A] IS NOT NULL)) </p>
<p>&emsp;簡単な例を示すと，リレーションスキーマ <b><span style="font-style: italic;">社員</span></b>(社員番号，社員名，所属，給与，マイナンバー)では，社員番号 や マイナンバー は候補キーでしょうが，もし 社員番号 を主キーと選べば リレーション 社員 のいかなるタップルの社員番号がNULLとなってはいけないというデータベースの一貫性制約が「キー制約」です．このとき，勿論，マイナンバー にも社員を一意識別する力はあるものの，主キーと指定されなかったので，NULLであってもよいということです．主キーとそう指定されなかった候補キーとの違いはこの一点です．<br />
&emsp;なお，主キーか否かを問わず，候補キーを構成している属性を<strong>キー属性</strong>と言い，キー属性でない属性を<strong>非キー属性</strong>と言います．候補キーと主キーを特段に区別する必要を感じないときには単に<strong>キー</strong>ということも多く，また特段に混乱をきたさないと考えられる場合には本来リレーションスキーマと書くべきところをリレーションと書いているところもあるのであらかじめ断っておきます．</p>
<p>&emsp;さて，定義1で候補キーの定義を与えましたが，その定義を<strong>関数従属性</strong>（functional dependency, FD）を使って表現し直すことができます．多少くどいかもしれませんが，その定義を記しておきます．</p>
<p><strong>【定義 3】</strong>（関数従属性，FD）<br />
&emsp;X，Y をリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の属性集合 Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> の部分集合とするとき，X から Y への FD がある，このことを X→Y と書く，とは次が成立するときをいう．ここに，iff は if and only if（必要かつ十分）を，⇒ は論理的含意を表し，X→Y の X を決定子（determinant），Y を被決定子（resultant）という．</p>
<p style="margin-top: -25px; margin-left: +150px;">X→Y iff (∀R∈<b><span style="font-style: italic;">R</span></b>)(∀t, t’∈R)( t[X]=t’[X] ⇒ t[Y]=t’[Y])</p>
<p>&emsp;また，FD については，Armstrong の公理系が成立することも皆さん，よくご存じのことと思います．</p>
<p><strong>【公理 1】</strong>（Armstrong の公理系）<br />
&emsp;A1.  Y⊆X ならば，X→Y である（反射律）．<br />
&emsp;A2.  X→Y かつ Z⊆W ならば，X∪W→Y∪Z である（添加律）．<br />
&emsp;A3.  X→Y かつ Y→Z ならば，X→Z である（推移律）．</p>
<p>&emsp;さて，定義 1 で候補キーの定義を与えましたが，FD を使ってこの定義を表現し直してみると，次のようになります．</p>
<p><strong>【定義 4】</strong>（FD を用いた候補キーの定義）<br />
&emsp;K⊆Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> がリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の候補キーと言われるのは，次が成立するときをいう．ここに，↛ は FD が成立しないことを表す．</p>
<p style="margin-top: -25px; margin-left: +50px;">(K→Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>) ∧ (∀H⊂K)(H↛Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>)</p>
<p>&emsp;さらに，この定義はリレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されたとき，属性集合 X の<strong>閉包</strong>（closure），これを X<sup>+</sup> と記す，を用いて以下のように書き直せます．</p>
<p>&emsp;まず，リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されたとき，<b><span style="font-style: italic;">R</span></b> の属性集合 X の閉包の求め方を示しておきます．このアルゴリズムの<strong>時間計算量</strong>（time complexity）は<b><span style="font-style: italic;">O</span></b>(n×p)，ここにn=|Ω<span style="font-style: italic;"><sub>R</sub></span>|，p=|<span style="font-style: italic;">F</span>|，と多項式オーダーであり<strong>扱いやすい問題</strong>（tractable problem）です．したがって X<sup>+</sup> は問題なく求められます．</p>
<p>&emsp;<strong>【X<sup>+</sup> を求めるアルゴリズム】</strong></p>
<p style="margin-top: -25px; margin-left: +50px;">ステップ 1　X<sup>(0)</sup>=X とおく．</p>
<p style="margin-top: -25px; margin-left: +50px;">ステップ 2　X<sup>(i)</sup>=X<sup>(i-1)</sup>∪{Z | Y→Z∈F ∧ Y⊆X<sup>(i-1)</sup> } (i≧1)</p>
<p style="margin-top: -25px; margin-left: +50px;">ステップ 3　もし X<sup>(i)</sup>=X<sup>(i-1)</sup> なら X<sup>＋</sup>=X<sup>(i-1)</sup> とおく．そうでなければステップ 2 に行く．</p>
<p>&emsp;ここで，関数従属性と閉包の関係性について記します．</p>
<p><strong>【命題 1】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとする．X, Y⊆Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> とするとき，次が成立する．</p>
<p style="margin-top: -25px; margin-left: +50px;">X→Y iff Y⊆X<sup>+</sup></p>
<p>（証明）<br />
&emsp;X<sup>+</sup> を求めるアルゴリズムでは，一般に X<sup>(i)</sup>=X<sup>(i-1)</sup>∪{Z | Y→Z∈F ∧ Y⊆X<sup>(i-1)</sup>} であるので，X<sup>(0)</sup>={X}としたとき X→Y∈<span style="font-style: italic;">F</span> ならば Y はX<sup>(1)</sup>の元となり，結果的にY⊆X<sup>+</sup>である．逆に，Y⊆X<sup>+</sup>ならば，X<sup>+</sup>の元は X に関数従属した属性からなるので，X→X<sup>+</sup>である．Y⊆X<sup>+</sup>なので反射律から X<sup>+</sup>→Y が成立する．従って，推移律から X→Y である．</p>
<p>&emsp;そうすると，定義 4で与えた FD を用いた候補キーの定義は閉包の概念を用いて定義 5 のように書き直せます．これは，命題 1 より，K→Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> iff K<sup>+</sup>=Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> が成立することから明らかでしょう．</p>
<p><strong>【定義 5】</strong>（閉包の概念を用いた候補キーの定義）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとする．K⊆Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> が <b><span style="font-style: italic;">R</span></b> の候補キーと言われるのは，次が成立するときをいう． </p>
<p style="margin-top: -25px; margin-left: +50px;">(K<sup>+</sup>=Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>) ∧ (∀H⊂K)(H<sup>+</sup>≠Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>)</p>
<p>&emsp;ここまで準備完了です．では，続けて，リレーションスキーマの候補キーを求める問題を考えてみましょう．2 つの立場から考察していきます．</p>
<table style="margin-top: -18px; border:none;">
<tbody>
<tr>
<td style="width: 60px; border:none; vertical-align: top; ">　(1)</td>
<td style="border:none;">
リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとき，<b><span style="font-style: italic;">R</span></b> の候補キーを（何でもよいので）<b>１つ</b>見つける．
</td>
</tr>
<tr>
<td style="border:none; vertical-align: top; ">　(2)</td>
<td style="border:none;">
リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとき，<b><span style="font-style: italic;">R</span></b> の候補キーを<strong>すべて</strong>見つける
</td>
</tr>
</tbody>
</table>
<h4>3. 候補キーを 1 つ見つける</h4>
<p><strong>【問題 1】（候補キーを 1 つ見つける）</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span>＝{f<sub>1</sub>, f<sub>2</sub>, <sub>…</sub>, f<sub>p</sub>}が指定されているとき，<b><span style="font-style: italic;">R</span></b> の候補キーを（何でもよいので）1 つ求めなさい．<br />
<b>（解答）</b><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> の全属性集合 Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> は <b><span style="font-style: italic;">R</span></b> のスーパーキーであることに着眼する．すると，次に示すアルゴリズムで候補キーが 1 つ見つかる．</p>
<p>&emsp;<strong>【候補キーを 1 つ見つけるアルゴリズム】</strong></p>
<table style="margin-top: -30px; border:none; margin-left: +40px;">
<tbody>
<tr>
<td style="width: 120px; border:none; vertical-align: top; ">ステップ 1</td>
<td style="border:none;">
K=Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> とおく．
</td>
</tr>
<tr>
<td style="border:none; vertical-align: top; ">ステップ 2</td>
<td style="border:none;">
属性A∈K を1つ選び，(K－A)<sup>+</sup> を計算する．もし，(K－A)<sup>+</sup>=Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> ならば，K=K－A とおいてステップ 2 に戻る．そうでなければ，K が求める候補キーである．ここに，－は差集合演算を表す．
</td>
</tr>
</tbody>
</table>
<p>&emsp;このアルゴリズムの正当性は明らかでしょう．注意するべき点は，どのような候補キーが返されるかはステップ 2 で取り除かれた属性 A の選択のされ方によることです．このような曖昧性はありますが，必ず候補キーは 1 つ返ってきます．このアルゴリズムの時間計算量は閉包を計算するアルゴリズムの時間計算量に依存し，それは多項式オーダーとなり扱いやすい問題です．</p>
<h4>4. 候補キーをすべて見つける</h4>
<p><strong>【問題 2】（候補キーをすべて見つける）</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span>＝{f<sub>1</sub>, f<sub>2</sub>, <sub>…</sub>, f<sub>p</sub>}が指定されているとき，<b><span style="font-style: italic;">R</span></b> の候補キーをすべて求めなさい．</p>
<p><strong>（解答）</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> の候補キーをすべて求めるアルゴリズムを以下に示します．</p>
<p><strong>【候補キーをすべて見つけるアルゴリズム】</strong></p>
<table style="margin-top: -30px; border:none; margin-left: +40px;">
<tbody>
<tr>
<td style="width: 120px; border:none; vertical-align: top; ">ステップ 1</td>
<td style="border:none;">
Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> の<ruby>冪<rt style="background-color: #DDDDDD;">べき</rt></ruby>集合 2<sup>Ω<span style="font-style: italic;"><b><sub>R</sub></b></span></sup> の元をその構成要素の数 i (i=0, 1, <sub>…</sub>, |Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|)で類別して，S<sub>0</sub>，S<sub>1</sub>，…, S<sub>|Ω<span style="font-style: italic;"><b><sub>R</sub></b></span>|</sub>を作る．すなわち，2<sup>Ω<span style="font-style: italic;"><b><sub>R</sub></b></span></sup> = S<sub>0</sub>∪S<sub>1</sub>∪ <sub>…</sub> ∪S<sub>|Ω<span style="font-style: italic;"><b><sub>R</sub></b></span>|</sub>である．
</td>
</tr>
<tr>
<td style="border:none; vertical-align: top; ">ステップ 2</td>
<td style="border:none;">
i∈{1, <sub>…</sub>, |Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|}に対して i=1 から始めて順次，次の処理をする．<br />
S<sub>i</sub>={X<sub>i,1</sub>, X<sub>i,2</sub>, <sub>…</sub>, X<sub>i,ni</sub>}の各元 X<sub>i,j</sub> に対して X<sub>i,j</sub><sup>+</sup> を計算する．ここに，n<sub>i</sub>=<sub>|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|</sub>C<sub>i</sub> (=|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|! / (i!×(|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|－i)!)) は組合せ（combination）を表す．このとき，もし X<sub>i,j</sub><sup>+</sup>=Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>なら，X<sub>i,j</sub> は候補キーである．このとき，各|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|≧k≧i+1であるkに対して，S<sub>k</sub>=S<sub>k</sub>－{Y∈S<sub>k</sub>|Y⊃X<sub>i,j</sub> }とS<sub>k</sub> を再編成する（つまり，X<sub>i,j </sub>を含むスーパーキーをこの後の候補キー探索処理から除外する）．
</td>
</tr>
<tr>
<td style="border:none; vertical-align: top; ">ステップ 3</td>
<td style="border:none;">
ステップ 2 の操作が終了した時点で得られていた候補キーが求める結果である．
</td>
</tr>
</tbody>
</table>
<p style="margin-top: -40px; ">
&emsp;このアルゴリズムは Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> のすべての部分集合（空集合を除く）について，その濃度の小さい方から大きい方の順，すなわちS<sub>1</sub>，S<sub>2</sub>，…, S<sub>|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|</sub> の順に，S<sub>i</sub> の各元が候補キーとなっているか否かを総当たりで検証していくこと（S<sub>i</sub>の任意の 2元 X<sub>i,j</sub> と X<sub>i,k</sub> が包含関係になることはないのでどちらかが他方のスーパーキーになることはないことに注目すること），そして S<sub>k</sub>を再編成することでスーパーキーを除外していることから，その正当性は明らかでしょう．しかし，それが故に，その時間計算量は指数オーダーとなり，<strong>扱いにくい問題</strong>（intractable problem）となります．</p>
<p>&emsp;さて，復習がてらに上述のアルゴリズムを使って，候補キーをすべて求める問題と解を 2 つ例示しましょう．
</p>
<p><strong>【例題 1】</strong>（データベーススペシャリスト平成29年春期 午前Ⅱ 問4）<br />
関係 R(A，B，C，D，E)において，<br />
&emsp;関数従属 {A，B}→C，{B，C}→D，D→{A，E}<br />
が成立する．これらから決定できるRの候補キーを全て挙げたものはどれか．<br />
&emsp;{A，B，C}<br />
&emsp;{A，B}，{B，C}<br />
&emsp;{A，B}，{B，C}，{B，D}<br />
&emsp;{B，C}，{C，D}</p>
<p><strong>（解答）</strong><br />
&emsp;{A，B}，{B，C}，{B，D} が正解である．<br />
&emsp;これを本稿に示した「候補キーをすべて見つけるアルゴリズム」に則り示すと次の通りである．なお，見やすさのために，{A，B} を AB，{A，B}→C を AB→C という具合に表現し直している．<br />
&emsp;まず，ステップ 1 の処理をする．<br />
&emsp;Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>={ A，B，C，D，E }なので，|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|=5，Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> の<ruby>冪<rt style="background-color: #DDDDDD;">べき</rt></ruby>集合 2<sup>Ω<span style="font-style: italic;"><b><sub>R</sub></b></span></sup> の元を構成要素数で類別して，S<sub>i</sub>，i=0～5を作ると， S<sub>0</sub>=Φ（空集合），S<sub>1</sub>={A，B，C，D，E}，S<sub>2</sub>={AB, AC, AD, AE, BC, BD, BE, CD, CE, DE, ABC}，S<sub>3</sub>={ABD, ABE, ACD, ACE, ADE, BCD, BCE, BDE, CDE}，S<sub>4</sub>={ABCD, ABCE, ABDE, ACDE, BCDE}，S<sub>5</sub>={ABCDE}となる．すなわち，2<sup>Ω<span style="font-style: italic;"><b><sub>R</sub></b></span></sup> = S<sub>0</sub>∪S<sub>1</sub>∪S<sub>2</sub>∪S<sub>3</sub>∪S<sub>4</sub>∪S<sub>5</sub>である．<br />
&emsp;続いて，ステップ 2 の処理をする．<br />
&emsp;まず，S<sub>1</sub> に対してステップ 2 の処理をすると，結果は次のとおりである．<br />
&emsp;A<sup>+</sup>=A，B<sup>+</sup>=B，C<sup>+</sup>=C，D<sup>+</sup>=ADE，E<sup>+</sup>=E．つまり，候補キーはない．<br />
&emsp;続いて，S<sub>2</sub> に対しての処理結果は次のとおりである．<br />
&emsp;<b>AB<sup>+</sup>=ABCDE</b>, AC<sup>+</sup>=AC, AD+=ADE, AE<sup>+</sup>=AE, <b>BC<sup>+</sup>=ABCDE</b>, <b>BD<sup>+</sup>=ABCDE</b>, BE<sup>+</sup>=BE, CD<sup>+</sup>=ACDE, CE<sup>+</sup>=CE, DE<sup>+</sup>=ADE．つまり，AB，BC，BD が候補キーであることが分かった．そこで，S<sub>3</sub>～S<sub>5</sub> の再編作業を行う．まず，S<sub>3</sub> については，AB，BC，BD を含む要素を S<sub>3</sub>から除外して改めて S<sub>3</sub> を作成すると次のとおりである．S<sub>3</sub>={ACD, ACE, ADE, CDE}．S<sub>4</sub> と S<sub>5</sub> に対しても同様な操作を行い，S<sub>4</sub>={ACDE}, S<sub>5</sub>=Φ となる．<br />
&emsp;続いて，再編成された S<sub>3</sub> に対してステップ 2 の処理をすると次のとおりである．<br />
&emsp;ACD<sup>+</sup>=ACDE, ACE<sup>+</sup>=ACE, ADE<sup>+</sup>=ADE, CDE<sup>+</sup>=ACDE．つまり，候補キーはない．<br />
&emsp;続いて，S<sub>4</sub> の処理を行うと，ACDE<sup>+</sup>=ACDE であり，候補キーはない．<br />
&emsp;S<sub>5</sub>=Φ なので候補キーはない．<br />
&emsp;よって，AB，BC，BD が <b><span style="font-style: italic;">R</span></b> の候補キーの全てであることが分かる．</p>
<p><strong>【例題 2】</strong>（2 の<ruby>冪<rt style="background-color: #DDDDDD;">べき</rt></ruby>乗個の候補キーが見つかる例）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>, B<sub>1</sub>, B<sub>2</sub>)に所与の関数従属性 A<sub>i</sub>→B<sub>i</sub>，B<sub>i</sub>→A<sub>i</sub> (i=1, 2)が指定されているとする．<b><span style="font-style: italic;">R</span></b> の候補キーをすべて求めなさい．</p>
<p><strong>（解答）</strong><br />
&emsp;Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>={A<sub>1</sub>, A<sub>2</sub>, B<sub>1</sub>, B<sub>2</sub>}とすると，S<sub>0</sub>=Φ，S<sub>1</sub>={A<sub>1</sub>, A<sub>2</sub>, B<sub>1</sub>, B<sub>2</sub>}，S<sub>2</sub>={ A<sub>1</sub>A<sub>2</sub>, A<sub>1</sub>B<sub>1</sub>, A<sub>1</sub>B<sub>2</sub>, A<sub>2</sub>B<sub>1</sub>, A<sub>2</sub>B<sub>2</sub>, B<sub>1</sub>B<sub>2</sub>}，S<sub>3</sub>={A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>, A<sub>1</sub>A<sub>2</sub>B<sub>2</sub>, A<sub>1</sub>B<sub>1</sub>B<sub>2</sub>, A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>}，S<sub>4</sub>={ A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>}となる．<br />
&emsp;そこで，S<sub>1</sub> の各元に対してその閉包を計算する．A<sub>i</sub><sup>+</sup>=A<sub>i</sub>B<sub>i</sub> (i=1,2)，B<sub>i</sub><sup>+</sup>=A<sub>i</sub>B<sub>i</sub> (i=1,2)であり，候補キーではない．そこで，S<sub>2</sub> の各元に対してその閉包を計算する．A<sub>1</sub>A<sub>2</sub><sup>+</sup>=A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>, A<sub>1</sub>B<sub>1</sub><sup>+</sup>=A<sub>1</sub>B<sub>1</sub>, A<sub>1</sub>B<sub>2</sub><sup>+</sup>=A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>, A<sub>2</sub>B<sub>1</sub><sup>+</sup>=A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>, A<sub>2</sub>B<sub>2</sub><sup>+</sup>=A<sub>2</sub>B<sub>2</sub>, B<sub>1</sub>B<sub>2</sub><sup>+</sup>=A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>となる．従って，A<sub>1</sub>A<sub>2</sub>, A<sub>1</sub>B<sub>2</sub>, A<sub>2</sub>B<sub>1</sub>, B<sub>1</sub>B<sub>2</sub> が候補キーであることが分かる．S<sub>3</sub> の再編作業を行うと S<sub>3</sub> は Φ となるので，ここで処理が終了する．</p>
<p>&emsp;例題 2 を一般化してすべての候補キーを求める問題の時間計算量について補足説明を行います．リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>, ···, A<sub>n</sub>, B<sub>1</sub>, B<sub>2</sub>, ・・・, B<sub>n</sub>)に所与の関数従属性集合 <span style="font-style: italic;">F</span> = {A<sub>i</sub>→B<sub>i</sub>, B<sub>i</sub>→A<sub>i</sub>|i∈{1, 2, <sub>…</sub>, n}}が指定された場合，<b><span style="font-style: italic;">R</span></b> は，A<sub>1</sub>A<sub>2</sub>・・・A<sub>n</sub>, B<sub>1</sub>A<sub>2</sub>・・・A<sub>n</sub>, A<sub>1</sub>B<sub>2</sub>A<sub>3</sub>・・・A<sub>n</sub>, ・・・, B<sub>1</sub>B<sub>2</sub>・・・B<sub>n</sub>と 2<sup>n</sup>個の候補キーを有することになるので，n が大きくなると実用的でなくなります．つまり，例題 2 では n=2 なので候補キーの数は 2<sup>2</sup>=4 で済みましたが，このようなタイプの関数従属性集合 <span style="font-style: italic;">F</span> を指定されたリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の候補キーの数は 2<sup>n</sup>なので，n が大きくなるにつれて，それ数え上げるには指数時間かかり，一般にすべての候補キーを求める問題は扱いにくい問題であることが直感できると思います．</p>
<h4>5. 候補キーの数の上限は？</h4>
<p>&emsp;1 つのリレーションスキーマには幾つ候補キーが存在しうるのか，その上限について次の結果[2, 3]が示されているので，紹介しておきたいと思います．</p>
<p><strong>【命題 2】</strong>（候補キーの数の上限）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> の候補キーの数は高々 <sub>n</sub>C<sub>⌊n/2⌋</sub>である．ここに，C は組合せ，⌊r⌋ は r を越えない最大の自然数を表し，|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|=n とする．<br />
<strong>（証明）</strong><br />
&emsp;濃度 n の集合 S において，候補キーの集合はお互いが集合の包含関係にないという意味でスパナー族（Sperner family）をなし，従って，比較不可能な S の部分集合の数は高々 <sub>n</sub>C<sub>⌊n/2⌋</sub> となる．</p>
<p>&emsp;例えば，n=2 なら <sub>n</sub>C<sub>⌊n/2⌋</sub>=2 であるので，候補キーの数は高々 2 です．<b><span style="font-style: italic;">R</span></b>(A, B)とすれば，もし上限の 2 個の候補キーがあった場合には，それらは {A} と {B} です．n=3 なら <sub>n</sub>C<sub>⌊n/2⌋</sub>=3 であるので，<b><span style="font-style: italic;">R</span></b>(A, B, C)とすれば，もし上限の 3 個の候補キーがあった場合には，それらは {A, B}，{A, C}，{B, C} です．n=4 なら <sub>n</sub>C<sub>⌊n/2⌋</sub>=6 であるので，<b><span style="font-style: italic;">R</span></b>(A, B, C, D)とすれば，もし上限の 6 個の候補キーがあったとすれば，それらは {A, B}，{A, C}，{A, D}，{B, C}，{B, D}，{C, D}です．<b><span style="font-style: italic;">R</span></b>(A, B, C, D, E)とすれば，n=5 で <sub>5</sub>C<sub>⌊5/2⌋</sub>=10 であるので，もし上限の 10 個の候補キーがあったとすれば，それらは {A, B}，{A, C}，{A, D}，{A, E}, {B, C}，{B, D}，{B, E}, {C, D}, {C, E}, {D, E} です．例題 2 の候補キーの数は 4 でしたが，2<sup>2</sup>＜<sub>4</sub>C<sub>2</sub>=6 とこの結果に符合しています．</p>
<h4>6. おわりに</h4>
<p>&emsp;リレーションの候補キーを求める問題を論じました．リレーションスキーマに所与の関数従属性集合が指定されたとき，候補キーを 1 つ見つけるためのアルゴリズムと，候補キーをすべて見つけるアルゴリズムを提示しました．上に見たように，同じく候補キーを求める問題ではあるのですが，「候補キーを 1 つ見つける問題」の時間計算量は多項式オーダーなので扱いやすい問題ですが，「候補キーをすべて見つける問題」の時間計算量は指数オーダーとなり扱いにくい問題であることを示しました．つまり，すべての候補キーを求めようとすると，リレーションスキーマの全属性数が小さいときには問題となりませんが，それが大きくなるととてつもない時間を要することとなり，現実的ではなくなるということです．とりあえず，候補キーが「1 つ」見つかればよいというなら話は簡単そうですが，「すべて」と言われると気長に根気よく見つけていくしか<ruby>術<rt style="background-color: #DDDDDD;">すべ</rt></ruby>はなさそうですね．</p>
<p>【文献】</p>
<p style="margin-top: -10px;" >[1]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
増永良文．リレーショナルデータベース入門[第3版]．サイエンス社，2017.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[2]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
J. Demetrovics. On the equivalence of candidate keys with Sperner systems. Acta Cybernetica 4, pp.247-252, 1979.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[3]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
J. Demetrovics and G.O.H. Katona. A survey of some combinatorial results concerning functional dependencies in database relations. Annals of Mathematics and Artificial Intelligence 7, pp.63-82, 1993.
</td>
</tbody>
</table>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
