SQLアンチパターン読書会
第10章 サーティワンフレーバー(31のフレーバー)
2013/10/17
ふじもと たかひさ Twitter:@tkfuji

1
アンチパターンの目的
サーティワンフレーバーの目的は列を特定の値に限定
すること。
値リストを列のデータ型や制約の宣言時に行うことで
(値リストにない)無効な文字列の入力を防止でき
る。

2
敬称列の例
値の種類が少ない列、連絡先情報テーブルの敬称
(salutation)列が典型。
31-Flavors/intro/create-table.sql
CREATE TABLE PersonalContacts (
-- 他の列. ....
敬称列の例
上司からあなたに与えられたタスク:新しい敬称をサポート
するために連絡先テーブルを変更せよ
敬称(salutation)列の現在の値
Mr. , Mrs. , Ms. , Dr. (博士), Rev. (聖職者)
フランスに支社を開...
バスキン・ロビンス社のサーティワンアイスクリーム
バスキン・ロビンス社が毎月日替わりで違う種類のアイスクリー
ムが食べられる。キャッチフレーズ「31のフレーバー」
現在、21種類の定番フレーバー、12種類のシーズン限定フレー
バー、16種類の地...
アンチパターン
アンチパターン:限定する値を列定義で指定する。
有効なデータ値を列の定義時に指定する方法を取る。例えば、
CHECK制約を定義する。CHECK制約により制約条件がFALSE
になる値の挿入や更新を拒否する。
31-Flavors...
アンチパターンの実現方法
CHECK制約を用いる。
ENUMと呼ばれる非標準のデータ型を用いる(MySQL固
有?)。
ドメイン(DOMAIN)を用いる。
ユーザー定義型(UDT)を用いる。
許可する値を指定したトリガーを記述する。
⇒上記には...
アンチパターンの短所
シンプルなクエリでは完全なリストを取得できない場
合がある。
31-Flavors/anti/create-table-check.sql
SELECT DISTINCT status FROM Bugs;

⇒全てのバグ...
アンチパターンの短所
メタデータの定義を取得する。MySQLではシステム
ビューinformation_schemaを検索する。
31-Flavors/anti/information-schema.sql
SELECT column_type...
新しいフレーバーの追加
ENUMやCHECK制約で値を追加、削除はできな
い。
31-Flavors/anti/add-enum-value.sql
ALTER TABLE Bugs MODIFY COLUMN status
ENUM('NEW...
アンチパターンは移植が困難
データベース製品間で仕様が異なる。
CHECK制約
ENUM
ドメイン(DOMAIN)
ユーザー定義型(UDT)
トリガー
11
アンチパターンは移植が困難
ふじもと調べ
アンチパターンの対応状況(○:対応、 :非対応)
ANSI
Postgre
SQL 標準
SQL
CHECK制約
ENUM
DOMAIN
UDT

SQL89で
標準化
なし
SQL92で
標準化
SQ...
CHECK制約の実装状況
ふじもと調べ
PostgreSQL
特定の列の値がブーリアン(真の値)の式を満たすように指定できる。列制約またはテーブル制約と
して指定可能。ただし、列制約として定義してもテーブル制約として管理される。
MySQL
な...
CHECK制約の実装状況
ふじもと調べ
SQL Serverのマニュアルから
「列に格納される値を制御するという点では、CHECK 制約は FOREIGN
KEY 制約に似ています。異なる点は、有効な値を決定する方法です。
FOREIGN KE...
ENUMの実装状況
ふじもと調べ
PostgreSQL
8.3からサポート。CREATE TYPEコマンドで実現。列挙型内の値の順序はその型が作成された時
に値を列挙した順番になる。
MySQL
文字列タイプのひとつ。文字列タイプにはCHAR、...
ドメイン(DOMAIN)の
実装状況 ふじもと調べ
PostgreSQL
CREATE DOMAINコマンドで実現。DEFAULT句、NOT NULL制約、
CHECK制約などを定義する。
CREATE DOMAIN name [ AS ] d...
ユーザー定義型( UDT)の
実装状況 ふじもと調べ
PostgreSQL
CREATE TYPEコマンドで実現。定義が面倒。
MySQL
なし。
Oracle
CREATE TYPE文とCREATE TYPE BODY文を使用する。CREAT...
アンチパターンの見つけ方
「アプリケーションメニューの選択肢を1つ追加するには、データベースを
オフラインにしなければならない。すべてがうまくいけば、30分もかから
ないはずだ」
⇒列の定義時に値が指定されている。サービス中断は本来必要ない。
...
アンチパターンを用いてよい場合
有効値の変更が不要だと断言できる場合はアンチパターンを用い
てよい。
例えば、相互排他的な2つの値(左/右、有効/無効、オン/
オフ、内部/外部)を指定する場合など。

19
解決策:限定する値をデータ
で指定する
参照するテーブルBugStatusを作成し、許可する値
をstatus列に格納する。Bugs.statusに
BugStatusを参照する外部キー制約を宣言する。
31-Flavors/soln/crea...
解決策での値セットの取得
シンプルなクエリで値リストを取得できる。
31-Flavors/soln/query-canonical-values.sql
SELECT status FROM BugStatus ORDER BY status;...
解決策での値追加
INSERT文で値を追加できる。テーブルへのアクセス遮断も不
要。
31-Flavors/soln/insert-value.sql
INSERT INTO BugStatus (status) VALUES ('DUPLIC...
解決策での値削除
Bugsテーブルから参照されている場合、削除できない。
BugStatusにactive列(有効/無効)を追加する。
31-Flavors/soln/inactive.sql
ALTER TABLE BugStatus ADD...
31のフレーバーなのか?
ふじもと調べ
バスキン・ロビンス社が毎月日替わりで違う種類のアイスクリー
ムが食べられる。キャッチフレーズ「31のフレーバー」
現在、21種類の定番フレーバー、12種類のシーズン限定フレー
バー、16種類の地域限定フレ...
31のフレーバーか?
サーティワンアイスクリーム行ってみた

南砂町店(江東区)
32種類でした!4 4(写真) 2
25
バスキン・ロビンス社のサーティワンアイスクリームの
豆知識 ふじもと調べ(Wikipediaを参考)
創業者がバートン・バスキンとアーヴィン・ロビンス。 バートン・バスキンはアーヴィン・ロビンス
の義理の兄(姉の夫)。
アーヴィン・ロビンスの父...
アンチパターンを31のフレーバーに用
いてはいけない理由 ふじもと考察
1000種類以上の開発済みのフレーバーから32種類のフレーバ
ーが販売される。
今月のフレーバーは月単位で入れ替えあり。
シーズン限定フレーバーは季節単位で入れ替えあり。
...
31のフレーバーは解決策参照テーブル
で実現するべき

どうやって実現
するかは宿題!
28
31のフレーバーは解決策参照テーブル
で実現するべきヒント(≒答え)
販売明細テーブルにフレーバーを示すカラムがある。これをアンチパターン
(フレーバーを示すカラムに値リストを設定)を用いないで解決する。
1000種類以上の開発済みのフレーバー...
おまけ:SQLデモ
本のサンプルコードを基に ENUMとCHECK制約のアンチパタ
ーンのSQL作成。
本のサンプルコードは実行可能でないものも含まれるため。
http://www.oreilly.co.jp/books/
9784873115...
Upcoming SlideShare
Loading in...5
×

SQLアンチパターン読書会 第10章 サーティワンフレーバー

1,266

Published on

2013年10月17日開催のSQLアンチパターン読書会 の資料。「第10章 サーティワンフレーバー(31のフレーバー)」。

Published in: Education
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,266
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
11
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

SQLアンチパターン読書会 第10章 サーティワンフレーバー

  1. 1. SQLアンチパターン読書会 第10章 サーティワンフレーバー(31のフレーバー) 2013/10/17 ふじもと たかひさ Twitter:@tkfuji 1
  2. 2. アンチパターンの目的 サーティワンフレーバーの目的は列を特定の値に限定 すること。 値リストを列のデータ型や制約の宣言時に行うことで (値リストにない)無効な文字列の入力を防止でき る。 2
  3. 3. 敬称列の例 値の種類が少ない列、連絡先情報テーブルの敬称 (salutation)列が典型。 31-Flavors/intro/create-table.sql CREATE TABLE PersonalContacts ( -- 他の列. . . salutation VARCHAR(4) CHECK (salutation IN ('Mr.', 'Mrs.', 'Ms.', 'Dr.', 'Rev.')), ); 3
  4. 4. 敬称列の例 上司からあなたに与えられたタスク:新しい敬称をサポート するために連絡先テーブルを変更せよ 敬称(salutation)列の現在の値 Mr. , Mrs. , Ms. , Dr. (博士), Rev. (聖職者) フランスに支社を開設⇒フランス後の敬称が新たに必要。 M. , Mme, , Mlle. など 来月ブラジルにも支社を開設予定⇒ポルトガル語も必要? 無停止でテーブル定義が修正できるか? 4
  5. 5. バスキン・ロビンス社のサーティワンアイスクリーム バスキン・ロビンス社が毎月日替わりで違う種類のアイスクリー ムが食べられる。キャッチフレーズ「31のフレーバー」 現在、21種類の定番フレーバー、12種類のシーズン限定フレー バー、16種類の地域限定フレーバー、今月のフレーバーと可変 になっている。 (何れも『SQLアンチパターン』の記述から) 5
  6. 6. アンチパターン アンチパターン:限定する値を列定義で指定する。 有効なデータ値を列の定義時に指定する方法を取る。例えば、 CHECK制約を定義する。CHECK制約により制約条件がFALSE になる値の挿入や更新を拒否する。 31-Flavors/anti/create-table-check.sql CREATE TABLE Bugs ( -- 他の列. . . status VARCHAR(20) CHECK (status IN ('NEW', 'IN PROGRESS', 'FIXED')) ); 6
  7. 7. アンチパターンの実現方法 CHECK制約を用いる。 ENUMと呼ばれる非標準のデータ型を用いる(MySQL固 有?)。 ドメイン(DOMAIN)を用いる。 ユーザー定義型(UDT)を用いる。 許可する値を指定したトリガーを記述する。 ⇒上記には共通の短所がある。 7
  8. 8. アンチパターンの短所 シンプルなクエリでは完全なリストを取得できない場 合がある。 31-Flavors/anti/create-table-check.sql SELECT DISTINCT status FROM Bugs; ⇒全てのバグのステータスがNEWの場合、NEWし か返って来ない。 8
  9. 9. アンチパターンの短所 メタデータの定義を取得する。MySQLではシステム ビューinformation_schemaを検索する。 31-Flavors/anti/information-schema.sql SELECT column_type FROM information_schema.columns WHERE table_schema = 'bugtracker_schema' AND table_name = 'bugs' AND column_name = 'status'; ⇒全てのバグのステータスを含んだ文字列が返って来 る。ENUMで定義した文字列「ENUM('NEW', 'IN PROGRESS', 'FIXED')」をアプリケーションで解析して、値を抽出する。 9
  10. 10. 新しいフレーバーの追加 ENUMやCHECK制約で値を追加、削除はできな い。 31-Flavors/anti/add-enum-value.sql ALTER TABLE Bugs MODIFY COLUMN status ENUM('NEW', 'IN PROGRESS', 'FIXED', 'DUPLICATE'); 10
  11. 11. アンチパターンは移植が困難 データベース製品間で仕様が異なる。 CHECK制約 ENUM ドメイン(DOMAIN) ユーザー定義型(UDT) トリガー 11
  12. 12. アンチパターンは移植が困難 ふじもと調べ アンチパターンの対応状況(○:対応、 :非対応) ANSI Postgre SQL 標準 SQL CHECK制約 ENUM DOMAIN UDT SQL89で 標準化 なし SQL92で 標準化 SQL99で 標準化 MySQL Oracle SQL Server DB2 UDB ○ × ○ ○ ○ ○ × × × ○ ○ × × × × ○ × ○ ○ ○ 12
  13. 13. CHECK制約の実装状況 ふじもと調べ PostgreSQL 特定の列の値がブーリアン(真の値)の式を満たすように指定できる。列制約またはテーブル制約と して指定可能。ただし、列制約として定義してもテーブル制約として管理される。 MySQL なし。「CHECK 条項は、全てのストレージ エンジンに解析されますが、無視されます。」( マニ ュアルから) Oracle 特定の列の値がブーリアン(真の値)の式を満たすように指定できる。列制約またはテーブル制約と して指定可能。 SQL Server 特定の列の値がブーリアン(真の値)の式を満たすように指定できる。列制約またはテーブル制約と して指定可能。 DB2 UDB 列制約またはテーブル制約として指定可能。チェック条件は2MBのCLOBとして管理。 13
  14. 14. CHECK制約の実装状況 ふじもと調べ SQL Serverのマニュアルから 「列に格納される値を制御するという点では、CHECK 制約は FOREIGN KEY 制約に似ています。異なる点は、有効な値を決定する方法です。 FOREIGN KEY 制約では別のテーブルから有効な値の一覧が取得されます が、CHECK 制約では論理式から有効な値が決定されます。」 ⇒CHECK制約(アンチパターン)の代替として  参照テーブル(解決策)が提示されている。 14
  15. 15. ENUMの実装状況 ふじもと調べ PostgreSQL 8.3からサポート。CREATE TYPEコマンドで実現。列挙型内の値の順序はその型が作成された時 に値を列挙した順番になる。 MySQL 文字列タイプのひとつ。文字列タイプにはCHAR、VARCHAR、BINARY、VARBINARY、 BLOB、TEXT、ENUM、SETがある。 ENUMはテーブルを作成する際カラム仕様の中で明確に列挙された許容値リストから選択された値を 持つ文字列オブジェクトである。ENUM('one', 'two', 'three') のように1つのENUMは最大 65,535エレメントを持つことができる。 許容値の文字列または1から始まるインデックス値(定義順)で挿入が可能。許容しない値は特別エ ラー値として空文字(インデックス値は0)が登録される(ストリクトSQLモードを有効にすること より挿入を禁止することも可能)。NULL値のインデックス値はNULL。 Oracle / SQL Server / DB2 UDB なし。 15
  16. 16. ドメイン(DOMAIN)の 実装状況 ふじもと調べ PostgreSQL CREATE DOMAINコマンドで実現。DEFAULT句、NOT NULL制約、 CHECK制約などを定義する。 CREATE DOMAIN name [ AS ] data_type [ COLLATE collation ] [ DEFAULT expression ] [ constraint [ ... ] ] constraintは、次のようになります。 [ CONSTRAINT constraint_name ] { NOT NULL | NULL | CHECK (expression) } ※ COLLATEは9.1から、CHECKは7.4から MySQL / Oracle / SQL Server / DB2 UDB なし。 16
  17. 17. ユーザー定義型( UDT)の 実装状況 ふじもと調べ PostgreSQL CREATE TYPEコマンドで実現。定義が面倒。 MySQL なし。 Oracle CREATE TYPE文とCREATE TYPE BODY文を使用する。CREATE TYPE BODY文でPL/ SQLを使用して定義する。 SQL Server CREATE TYPEステートメントを使用する。C#やVBの.NETプログラミング言語で、UDT の作 成の仕様を満たすクラスまたは構造体を作成する。 DB2 UDB ユーザー定義の構造化タイプ。CREATE DISTINCT TYPEステートメントを使用する。既存のデ ータ・タイプを基に定義する。UDF(ユーザー定義関数)でUDTの振る舞いを定義する。 17
  18. 18. アンチパターンの見つけ方 「アプリケーションメニューの選択肢を1つ追加するには、データベースを オフラインにしなければならない。すべてがうまくいけば、30分もかから ないはずだ」 ⇒列の定義時に値が指定されている。サービス中断は本来必要ない。 「status列は、以下の値のうちの1つを持つことができる。このリストの 修正が必要になることは、まずないはずだ」 ⇒曖昧な表現。状況が変われば修正が必要になるかも。 「アプリケーションコード側の値リストが、ビジネスルールと同期していな い。これで何度目だろう」 ⇒異なる場所で情報を二重管理していると生じるリスク。 18
  19. 19. アンチパターンを用いてよい場合 有効値の変更が不要だと断言できる場合はアンチパターンを用い てよい。 例えば、相互排他的な2つの値(左/右、有効/無効、オン/ オフ、内部/外部)を指定する場合など。 19
  20. 20. 解決策:限定する値をデータ で指定する 参照するテーブルBugStatusを作成し、許可する値 をstatus列に格納する。Bugs.statusに BugStatusを参照する外部キー制約を宣言する。 31-Flavors/soln/create-lookup-table.sql CREATE TABLE BugStatus ( status VARCHAR(20) PRIMARY KEY ); INSERT INTO BugStatus (status) VALUES ('NEW'), ('IN PROGRESS'), ('FIXED'); CREATE TABLE Bugs ( -- 他の列. . . status VARCHAR(20), FOREIGN KEY (status) REFERENCES BugStatus(status) ON UPDATE CASCADE ); 20
  21. 21. 解決策での値セットの取得 シンプルなクエリで値リストを取得できる。 31-Flavors/soln/query-canonical-values.sql SELECT status FROM BugStatus ORDER BY status; ⇒全てのバグのステータスがBugsでNEWの場合  でも全ての値が取得可能。 21
  22. 22. 解決策での値追加 INSERT文で値を追加できる。テーブルへのアクセス遮断も不 要。 31-Flavors/soln/insert-value.sql INSERT INTO BugStatus (status) VALUES ('DUPLICATE'); 22
  23. 23. 解決策での値削除 Bugsテーブルから参照されている場合、削除できない。 BugStatusにactive列(有効/無効)を追加する。 31-Flavors/soln/inactive.sql ALTER TABLE BugStatus ADD COLUMN active ENUM('INACTIVE', 'ACTIVE') NOT NULL DEFAULT 'ACTIVE'; DELETEではなくUPDATEを使う。 31-Flavors/soln/update-inactive.sql UPDATE BugStatus SET active = 'INACTIVE' WHERE status = 'DUPLICATE'; 有効なものだけ検索する。 31-Flavors/soln/select-active.sql SELECT status FROM BugStatus WHERE active = 'ACTIVE'; 23
  24. 24. 31のフレーバーなのか? ふじもと調べ バスキン・ロビンス社が毎月日替わりで違う種類のアイスクリー ムが食べられる。キャッチフレーズ「31のフレーバー」 現在、21種類の定番フレーバー、12種類のシーズン限定フレー バー、16種類の地域限定フレーバー、今月のフレーバーと可変 になっている。(上記は『SQLアンチパターン』の記述から) ⇒(日本)22種類の定番フレーバー、6種類のシーズン限定フレ ーバー、4種類の今月のフレーバー⇒合計32種類のフレーバー? ⇒(アメリカ)24種類の定番フレーバー、28種類のシーズン限 定フレーバー、5種類のチョイスフレーバー⇒合計57種類のフレ ーバー? (それぞれ日本とUSのWebサイトから) 24
  25. 25. 31のフレーバーか? サーティワンアイスクリーム行ってみた 南砂町店(江東区) 32種類でした!4 4(写真) 2 25
  26. 26. バスキン・ロビンス社のサーティワンアイスクリームの 豆知識 ふじもと調べ(Wikipediaを参考) 創業者がバートン・バスキンとアーヴィン・ロビンス。 バートン・バスキンはアーヴィン・ロビンス の義理の兄(姉の夫)。 アーヴィン・ロビンスの父親がアイスクリーム店を経営し、二人にアイスクリーム店開業を勧める。 その後、その二つの店が合併した。 アメリカでは「バスキン・ロビンス(Baskin-Robbins)」で通じるが、「サーティワン (thirty-one)」では通じない(thirty-oneの呼称自体無い)。日本と台湾では「サーティワ ン」で通じるが、「バスキン・ロビンス」では通じにくい。「サーティーワン」ではなく「サーティ ワン」。 日本ではアメリカのバスキン・ロビンス社日本法人と不二家(各43.27%の出資比率)の合弁会社が 経営。年間売上200億円(平均単価400円として5000万個の売上。1100店として一日当たり 125個の売上)。サーティワンアイスクリームが不二家との合弁であることが知られていないため、 「不二家の期限切れ原材料使用問題」による影響は比較的小さかった。 フレーバーの種類は1000種類以上。フレーバーは世界どこでも大抵32種 類から選べる(高速道路施設などの小規模店は除く)。 26
  27. 27. アンチパターンを31のフレーバーに用 いてはいけない理由 ふじもと考察 1000種類以上の開発済みのフレーバーから32種類のフレーバ ーが販売される。 今月のフレーバーは月単位で入れ替えあり。 シーズン限定フレーバーは季節単位で入れ替えあり。 定番フレーバーすら入れ替えが想定される。 32種類より少ないフレーバーを販売する店もある。 種別(定番・シーズン限定・今月)も管理したいだろう。 27
  28. 28. 31のフレーバーは解決策参照テーブル で実現するべき どうやって実現 するかは宿題! 28
  29. 29. 31のフレーバーは解決策参照テーブル で実現するべきヒント(≒答え) 販売明細テーブルにフレーバーを示すカラムがある。これをアンチパターン (フレーバーを示すカラムに値リストを設定)を用いないで解決する。 1000種類以上の開発済みのフレーバーを管理するフレーバーテーブル。フレー バー種別カラムを持つ。 地域フレーバーテーブル。地域テーブルとフレーバーテーブルと従属関係にある 子テーブル。年月を主キーとして加える(有効開始年月日でもよい)。 店舗フレーバーテーブル。地域フレーバーテーブルと店舗テーブルと従属関係に ある子テーブル。年月を主キーとして加える(有効開始年月日でもよい)。 販売明細は地域フレーバーテーブル(通常店の場合)か店舗フレーバーテーブル (小規模店の場合)と参照関係を持つ。 29
  30. 30. おまけ:SQLデモ 本のサンプルコードを基に ENUMとCHECK制約のアンチパタ ーンのSQL作成。 本のサンプルコードは実行可能でないものも含まれるため。 http://www.oreilly.co.jp/books/ 9784873115894/ PostgreSQLで実行。MySQLは(サンプルコードにある) CHECK制約が実行できないため。 30
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×