2012-07-06

MySQL Workbench の EER モデリングツールでリレーションシップ検証 3 (リレーションシップアイコンの種類と使い方)

前回、前々回の記事で、外部キーの設定と制約の定義方法について説明してきましたが、今回は EER モデリングツールのリレーションシップアイコンの種類と使い方について説明します。

EER モデリングでリレーションシップの設定を行う場合は、画面の左下に並ぶ 6 種類のアイコンを使います。




 既存のテーブル列を使ってリレーションシップを設定する

大抵の場合は、先に基本的なテーブルを予め定義しておき、後でリレーションシップを設定する作業手順となるでしょう。そのような場合は、上記赤囲みの一番下のアイコンを使用します。

このアイコンを使って作成されたリレーションは、たとえば次のようになります。




青囲みの列に注目してください。ブランドテーブルの [ブランドID]、および取扱商品テーブルの [ブランドID] は共に既存の列にが使われています。


 外部キー専用の列を子テーブルに新規追加し、1対1 の非依存型(non identifying)リレーションシップを設定する


子テーブルに外部キー用の列が作成されていない場合に、親テーブルと 1対1 の非依存型のリレーションシップを設定する場合は、一番上のアイコンをクリックします。
非依存型(non identifying)リレーションシップについては、こちらの記事をご覧ください。

このアイコンを使って作成されたリレーションは、たとえば次のようになります。



青囲みの列に注目してください。ブランドテーブルの [ブランドID]はそのままですが、取扱商品テーブルには、 [ブランド_ブランドID] という専用の列が新たに追加されています。
また、ブランドテーブル側、および取扱商品テーブル側の支線は枝分かれしていないため、このリレーションシップが 1対1 の関係となっていることがわかります。

非依存型リレーションシップの場合、コネクタは破線で表現されます。


 外部キー専用の列を子テーブルに新規追加し、1対多の非依存型(non identifying)リレーションシップを設定する

子テーブルに外部キー用の列が作成されていない場合に、親テーブルと 1対多の非依存型リレーションシップを設定する場合は、上から二番目のアイコンをクリックします。
非依存型(non identifying)リレーションシップについては、こちらの記事をご覧ください。

このアイコンを使って作成されたリレーションは、たとえば次のようになります。



青囲みの列に注目してください。ブランドテーブルの [ブランドID]はそのままですが、取扱商品テーブルには、 [ブランド_ブランドID] という専用の列が新たに追加されています。
また、ブランドテーブル側の支線が枝分かれしていないのに対し、取扱商品テーブル側の支線が三つに枝分かれしているため、ブランド 1 に対し、取扱商品が多の関係になっていることがわかります。

非依存型リレーションシップの場合、コネクタは破線で表現されます。


 外部キー専用の列を子テーブルに新規追加し、1対1 の依存型(identifying)リレーションシップを設定する

子テーブルに外部キー用の列が作成されていない場合に、親テーブルと 1対1 の依存型のリレーションシップを設定する場合は、上から三番目のアイコンをクリックします。
依存型(identifying)リレーションシップについては、こちらの記事をご覧ください。

このアイコンを使って作成されたリレーションは、たとえば次のようになります。



青囲みの列に注目してください。ブランドテーブルの [ブランドID]はそのままですが、取扱商品テーブルには、 [ブランド_ブランドID] という専用の列が新たに追加されています。
また、ブランドテーブル側、および取扱商品テーブル側の支線は枝分かれしていないため、このリレーションシップが 1対1 の関係となっていることがわかります。

依存型リレーションシップの場合、コネクタは実線で表現されます。


 外部キー専用の列を子テーブルに新規追加し、1対多の依存型(identifying)リレーションシップを設定する


子テーブルに外部キー用の列が作成されていない場合に、親テーブルと 1対多の依存型リレーションシップを設定する場合は、上から四番目のアイコンをクリックします。
依存型(identifying)リレーションシップについては、こちらの記事をご覧ください。

このアイコンを使って作成されたリレーションは、たとえば次のようになります。



青囲みの列に注目してください。ブランドテーブルの [ブランドID]はそのままですが、取扱商品テーブルには、 [ブランド_ブランドID] という専用の列が新たに追加されています。
また、ブランドテーブル側の支線が枝分かれしていないのに対し、取扱商品テーブル側の支線が三つに枝分かれしているため、ブランド 1 に対し、取扱商品が多の関係になっていることがわかります。

依存型リレーションシップの場合、コネクタは実線で表現されます。



 多対多のリレーションシップを設定する



子テーブルに外部キー用の列が作成されていない場合に、親テーブルと多対多のリレーションシップを設定する場合は、下から二番目のアイコンをクリックします。

このアイコンを使って作成されたリレーションは、たとえば次のようになります。




多対多の場合は、子テーブルの外部キーと親テーブルの主キーを結び付けると、テーブル名_has_テーブル名 という名前のテーブルが新たに作成されます。
このテーブルは、子テーブルに対する外部キーおよび親テーブルに対する外部キーをそれぞれ持っている点に注目してください。

上図の場合では、ブランド_has_取扱商品 というテーブルに、取扱商品テーブルの主キーに対する外部キー、およびブランドテーブルの主キーに対する外部キーが作成されることを示しています。


外部キーを確認すると、以下のようになっています。


○ブランドテーブルに対する外部キー



ブランドテーブルの主キー[ブランドID]に対する外部キーが作成されています。



○取扱商品テーブルに対する外部キー




取扱商品テーブルの主キー[商品ID]に対する外部キーが作成されています。



【関連リンク】
MySQL Workbench 基礎講習コース





2012-07-05

MySQL Workbench の EER モデリングツールでリレーションシップ検証 2 (外部キー制約の種類と動作)

前回の記事では、リレーションシップ構築時の idendifying (依存型)および non identifying (非依存型) の考え方と設計方法について述べましたが、今回は外部キーで設定可能な制約の種類と動作について説明します。


【外部キー制約とは】

子テーブル側の外部キーと、親テーブルの主キーの参照整合性を維持するために、子テーブル側の外部キーの動作を制限するものです。

たとえば、前回のブランドと取扱商品との関係性では、取扱商品テーブル側に不明な外部キー([ブランドID])が存在しないように制御したり、ブランドテーブル側から特定のブランドを削除した場合、そのブランドに関連する商品を取扱商品から自動的に連動して削除させたりといった振る舞い(制約)を設定します。


MySQL Workbench の EER モデリングでは、下図のように Foreign Key タブ上の Foreign Key Option を選択するだけで外部キー制約の設定が行えます。



【On Update と On Delete】

外部キー制約のオプションは、更新時(On Update)、削除時(On Delete)に大別されます。

これらは、親テーブル側(上図ではブランド)側の動作を示しており、親テーブル側のレコードが更新されたり(On Update)、削除されたり(On Delete)したときに、子テーブル(上図では取扱商品)の関連レコードの扱いを定義するという意味です。
そして、実際の関連レコードの扱いは、上図の赤囲みのドロップダウンリストから選択します。


【外部キー制約の種類】

ドロップダウンリストから選択可能な外部キー制約は次のとおりです。

RESTRICT/NO ACTION
子テーブルに関連レコードがあったら、親レコードの更新/削除を許可しない。

NO ACTION はステートメントおよびすべてのトリガーが起動された後に子テーブルの値がまだ有効であれば変更は許可される。
これに対し、RESTRICT は、子テーブルに関連レコードが存在する場合、変更は絶対に許可されない。
RDBMS ではこのような厳密な動作の違いがあるものもあるが、MySQL では RESTRICT と NO ACTION の挙動は同じ。


たとえば、取扱商品(子テーブル側)の登録を始めたら、ブランド名(親テーブル側)の変更をさせないようにする場合がこれに相当します。

CASCADE
親テーブルのレコードを更新/削除したら、子テーブルのレコードも更新/削除する。
厳密には、親テーブルの主キーの値を更新したら、子テーブルの外部キーの値も同じ値で更新され、親テーブルのレコードを削除したら、そのレコードに関連する子テーブルのレコードも連動して削除される。

たとえば、特定のブランド(親テーブル側)を削除したら、そのブランドを持つすべての取扱商品(子テーブル側)を削除するようにする場合がこれに相当します。

SET NULL
親テーブルのレコードを更新/削除したら、子テーブルの外部キーの値を NULL に設定する。
これにより、当該レコードの親子関係が解除されることになる。

たとえば、ブランド(親テーブル側)を削除したとしても、取扱商品(子テーブル側)は将来の管理用にデッドストックとして残しておく場合がこれに相当します。


親テーブルの主キーを変更した場合、および親レコードを削除した場合の外部キー制約の振る舞いを表にすると、以下のようになります。


動作条件挙動親(子なし)親(子あり)
On UpdateRESTRICT/NO ACTION親主キー更新可親主キー更新不可変化なし
CASCADE親主キー更新可親主キー更新可外部キー連動更新
SET NULL親主キー更新可親主キー更新可外部キーNULL
On DeleteRESTRICT/NO ACTION親レコード削除可親レコード削除不可変化なし
CASCADE親レコード削除可親レコード削除可子レコード連動削除
SET NULL親レコード削除可親レコード削除可外部キーNULL


【SQL による外部キー制約の例】


前述の外部キー制約のパターンのうちのいくつかを、実際の SQL による定義でいくつか確認してみましょう。太字が外部キーの設定と制約を定義している部分です。特に赤字の部分に注目してください。
挙動については、前項のテーブルをご覧ください。



例1: 
On Update: NO ACTION
On Delete: CASCADE

--
-- Table structure for table `取扱商品`
--

DROP TABLE IF EXISTS `取扱商品`;
SET @saved_cs_client     = @@character_set_client;
SET character_set_client = utf8;
CREATE TABLE `取扱商品` (
  `ブランドID` int(11) DEFAULT NULL,
  `商品ID` int(11) NOT NULL AUTO_INCREMENT,
  `商品名` varchar(45) CHARACTER SET utf8 DEFAULT NULL,
  PRIMARY KEY (`商品ID`),
  KEY `fk_取扱商品_ブランド` (`ブランドID`),
  CONSTRAINT `fk_取扱商品_ブランド` FOREIGN KEY (`ブランドID`) REFERENCES `ブランド` (`ブランドID`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;
SET character_set_client = @saved_cs_client;



例2: 
On Update: CASCADE
On Delete: SET NULL


--
-- Table structure for table `取扱商品`
--


DROP TABLE IF EXISTS `取扱商品`;
SET @saved_cs_client     = @@character_set_client;
SET character_set_client = utf8;
CREATE TABLE `取扱商品` (
  `ブランドID` int(11) DEFAULT NULL,
  `商品ID` int(11) NOT NULL AUTO_INCREMENT,
  `商品名` varchar(45) CHARACTER SET utf8 DEFAULT NULL,
  PRIMARY KEY (`商品ID`),
  KEY `fk_取扱商品_ブランド` (`ブランドID`),
  CONSTRAINT `fk_取扱商品_ブランド` FOREIGN KEY (`ブランドID`) REFERENCES `ブランド` (`ブランドID`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;
SET character_set_client = @saved_cs_client;


2012-07-04

MySQL Workbench の EER モデリングツールでリレーションシップ検証 1 (Identifying と Non identifying)

MySQL Workbench の便利な機能に EER モデリングツールがあります。


MySQL Workbench の EER モデリング例 


EER モデリングツールを使うことによって、データベースの基本設計を行い、それを使って MySQL  データベース本体を生成したり(フォワードエンジニアリング)、既存の MySQL データベースを EER モデリングツールに読み込ませて(リバースエンジニアリング)設計内容を修正した後で再び MySQL データベースに同期(シンクロナイジング)させたりすることができます。

EER モデリングツールの魅力は、何といってもデータベース設計を視覚的に行えるところにあることでしょう。
テーブル定義、列定義はもちろんのこと、テーブルオブジェクトの配置、リレーションシップの設定などもマウスクリックや簡単な入力作業である程度の設計が可能です。

MySQL Workbench は、MySQL の公式サイトからダウンロードできます。

ダウンロード先:MySQL Workbench 5.2


今回より、MySQL Workbench の EER モデリング機能で設定可能なリレーションシップの種類と、その動作の違いについて数回に分けて説明します。

リレーションシップの種類には、一対一、一対多、多対多、自己リレーションなどがありますが、それらの基本的な概念は他のサイトでも多く触れられているため、本記事では省略します。


【Identifying と Non identifying】

EER でリレーションシップ設定を行い、外部キーの設定情報を確認したときに以下のようなチェックボックスが気になった方もいらっしゃるのではないでしょうか。



そこで、今回は、上記のリレーションの外部キー属性となる、identifying と non identifying の違いについて説明します。


Identifying relationship (依存リレーションシップ)--- 子テーブルの外部キーの一部に親テーブルの主キーが組み込まれた形となり、親テーブルなしでは成り立たない関係。


たとえば、ブランド契約で販売する商品が、撤退時に商品の取扱いも同時に終了するように、ブランドテーブルと取扱い商品テーブルを関連づける場合、[商品ID] および[ブランドID] の組み合わせで外部キーを作り、[ブランドID]  が存在しなければその商品は存在し得ないような厳密な設計を行います。



本来、子テーブル側の主キーは一つ([商品ID])ですが、依存型リレーションシップの場合は親テーブル側のIDを識別するための列([ブランドID])も主キー扱いとなりますので、上図のように子テーブルの主キーは二つとなります(どちらも欠かせません)。
 
 EERモデリングでは、identifying リレーションのコネクタは、上図のように実線で表現されます。

 この場合、外部キー設定がされている取扱商品テーブル構成をダンプ(SQL表記)させると、以下のようになります。
 太字表記の部分が今回のチェック項目になりますが、特に赤字の部分に注目してください。[商品ID] および [ブランドID] の両方が主キー となっています。

--
-- Table structure for table `取扱商品`
--

DROP TABLE IF EXISTS `取扱商品`;
SET @saved_cs_client     = @@character_set_client;
SET character_set_client = utf8;
CREATE TABLE `取扱商品` (
  `ブランドID` int(11) NOT NULL,
  `商品ID` int(11) NOT NULL AUTO_INCREMENT,
  `商品名` varchar(45) CHARACTER SET utf8 DEFAULT NULL,
  PRIMARY KEY (`商品ID`,`ブランドID`),
  KEY `fk_取扱商品_ブランド` (`ブランドID`),
  CONSTRAINT `fk_取扱商品_ブランド` FOREIGN KEY (`ブランドID`) REFERENCES `ブランド` (`ブランドID`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
SET character_set_client = @saved_cs_client;


Non identifying relationship(非依存リレーションシップ)--- 親テーブルの主キーと子テーブルの外部キーでリレーションシップを構築するが、子テーブルに外部キーとは独立した主キーを持っている関係。


前述のモデルの応用例として、ブランド管理が廃止され商品だけが残った場合にも、在庫商品を処分(販売)できるように、ブランドを問わず商品を管理して扱う場合は、親テーブルが削除された場合にも、子テーブルの商品だけは残して管理できるように設計します。





EERモデリングでは、non-identifying リレーションのコネクタは、上図のように破線で表現されます。


この場合、外部キー設定がされている取扱商品テーブル構成をダンプ(SQL表記)させると、以下のようになります。
太字表記の部分が今回のチェック項目になりますが、特に赤字の部分に注目してください。[商品ID] のみが主キー となっています。
--
-- Table structure for table `取扱商品`
--


DROP TABLE IF EXISTS `取扱商品`;
SET @saved_cs_client     = @@character_set_client;
SET character_set_client = utf8;
CREATE TABLE `取扱商品` (
  `ブランドID` int(11) NOT NULL,
  `商品ID` int(11) NOT NULL AUTO_INCREMENT,
  `商品名` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`商品ID`),
  KEY `fk_取扱商品_ブランド` (`ブランドID`),
  CONSTRAINT `fk_取扱商品_ブランド` FOREIGN KEY (`ブランドID`) REFERENCES `ブランド` (`ブランドID`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET character_set_client = @saved_cs_client;



【関連リンク】
MySQL Workbench 基礎講習コース


2012-06-16

『売上猫くん on MySQL』開発日記 - 番外25 - 行ロックについて

小社主催の「FileMaker+MySQL開発の講習」の受講者の方から「FileMakerとMySQLのシステムで、FileMaker(単体システム)のような行ロックってできないの?」との質問を講習前に頂いた。
FileMaker単体のシステムでは、ユーザがあるレコードを編集中に他のユーザが同レコードを編集しようとしても「他のユーザが編集中」旨が表示され、他のユーザは先行するユーザが編集を終了するまで編集することができなくなる。質問の趣旨はこれをFileMaker/MySQLのシステムでも実現したいということ。 
FileMaker標準機能では、FileMaker/MySQL 環境下で排他的行ロックはできない。 が、方法としては2つある。一つはMySQLのロック機能(select for update)を使用する方法(MySQLの排他的行ロック)、もう一つはMySQLテーブルにロックフラグを用意し、最初に編集を開始したユーザがそのフラグに自分のIDを書き込み、後続の他ユーザの編集を禁じるようにごりごりスクリプトで制御方法(FileMaker単体の行ロックと似ているという意味で、FileMakerライクなロック)。 以下はこの2つのロックの実装方法について。

1.MySQLの排他的行ロック
まず、MySQLの排他的行ロック機能を使うと、FileMakerはどのように反応するのか、試してみる。

MySQLコマンドラインで、

  begin;
  select 売上No from 売上ヘッダ where 売上No=1 for update;


を実行する。 次にFileMakerの売上画面で売上No=1のレコードを開いてみると、何事もなく表示される。次にこのレコードの任意のフィールド値を変更してみると普通に変更できる。 さらに、レコードをCommitすると… 出た、必殺のコーヒーマーク! これがMySQLの排他的行ロックである。 ここで、MySQLコマンドラインで、


 commit;


を実行すると、コヒーマークは消えて、レコードがCommitされた。 MySQLの排他的行ロック(select for update)は他ユーザがレコードをselectすることを妨げず、よってFileMakerのレイアウト上にも表示される。 また一旦表示されたレコードは、他のユーザが編集していたとしても、後発ユーザの編集を妨げるよなFileMaker的ロックは行われない。 しかし、いざCommitを実行しようとすると、コーヒーマックが出て、select for update を実行したユーザのトランザクションがCommitかRollbackされるまで、コヒーマークが出たまま、つまりロックされた状態となる。
【FileMakerとMySQLコマンドライン】
select ~ for update 後にFMで編集→確定ボタンすると、コーヒーカップが… 
注:
通常、ロックが発生から60秒後に、「[MySQL][ODBC 5.1 Driver][mysqld-5.1.58-community]Lock wait timeout exceeded; try restarting transaction」というエラーが返る。レコード確定ステップ実行後に後処理がある場合は、このエラーをトラップして処理を中止するなど適切な処理を行わないと、システムが暴走する可能性があるので要注意
FileMakerからも「SQLを実行」スクリプトステップに上記内容を直書きしたり、ストアドプロシージャをCALLすれば、ロックやトランザクションを利用できる。試しに


BEGIN
start transaction;
 select * from 売上ヘッダ where 売上No=1 for update;
 select sleep(60);
 rollback;
END;


というストアドプロシージャを作成して、「SQLを実行」ステップからこれをCALLしてみる。 問題なく実行でき、結果、60秒の間そのレコードは更新できなくなる。しかし 「SQLを実行」 ステップはクライアントPCにDSN登録がないと実行できない、という問題があるため、FileMakerからMySQLトリガを発生させてストアドを実行したい(この方法については『売上猫くん on MySQL』開発日記 - 3 - FMからストアド、トリガを参照)。 ということでトリガから上記のストアドを実行しようとすると、「 Not allowed to return a result set from a trigger」というエラーが出るので、レコードセットが返らないように下記のようにストアドを書きなおした。

BEGIN
    declare temp int;
    start transaction;
        select Count(*) into temp from 売上ヘッダ where  売上No =1 for update;
        select sleep (60) into temp;
        update appliasons set ret="OK" where ID=appId;
    commit;
END
ところが残念なことが重なる。今度は「Explicit or implicit commit is not allowed in stored function or trigger.」というエラーが返ってくる。 これでMySQLのトリガではトランザクションが使用できないことがわかった。まえに小生が書いた記事『売上猫くん on MySQL』開発日記 - 番外12 - トリガの制約に、この件をちらっと書いていた(恥)。 
結論としては、ストアドを直接実行すればMySQLのロックを実行できるが、トリガを介したストアド実行によるロックは不可、ということになる。

尚、FM12の新関数ExecuteSQL関数では、MySQLのロックは利用できない(つか、この関数、相当中途半端な上、意味不明なクエリを発する。書いた通りの動きをしないこともあるし…。この辺りは後日機会があれば)。


2.FileMakerライクなロック
次にFileMakerライクなロック。これは開発者が自分でゴリゴリ書かなくてはならないのでかなり面倒だ。 以下は小社のFileMaker/MySQL講習テキストから実装方法を引用する。
【実装】
“編集”ボタンを用意し、レコードを変更する必要があるユーザには“編集”ボタンを実行して「編集モード」にすることを義務付ける。編集モードでなければレコードの変更は実行できないよう制御するとともに、“編集”ボタン実行時には、当該レコードのロックフラグフィールド(cntLockId)にユーザ固有のIDをセット。このフラグが解除されない間は他ユーザが当該レコードの変更を行えないように制御。ユーザがレコードの更新を終えCommitした瞬間にこのロックフラグフィールドを解除するように設計する。
名称
種類
仕様
cntLockId
フィールド
(
テキスト)
編集ボタンを実行するとこのフィールドにユーザ固有のID=Get ( 持続 ID )が入力され、このIDを持たない他ユーザは編集不可となる。 
cntLockTiime
フィールド
(
タイムスタンプ)
編集ボタン実行時に[cntLockId]とともに本フィールドにはサーバのタイムスタンプ(現日時)が入力される。 このタイムスタンプによりデッドロックになっていないかを判断し、管理者は適切な処理をおこなう。
cntLockAC
フィールド
(
テキスト)
必要に応じて作成。編集ボタン実行時にGet ( アカウント名 )が入力される。 これを利用すれば、編集実行者を画面上に表示することができる。
(ユーザが手入力可能なフィールド)
フィールド
OnObjectEnterスクリプトトリガを用いて、[cntLockId<> Get ( 持続 ID )の場合は、フィールドに入れない(フィールド値を変更できない)ように制御。
編集
ボタン
上記のcntLockId/ cntLockTiime/ cntLockAC参照。左記3フィールドに値を入力後にレコードを確定する。これによりそのレコードは他ユーザによる編集が不可となる。
確定
ボタン
上記のcntLockId/ cntLockTiime/ cntLockACの値をクリア(ロックを解除)後、レコードを確定する。
復帰
ボタン
デッドロックしないよう([cntLockId]の値が残らない)ように制御。
他のボタン
ボタン
削除ボタン、削ボタン(売上明細削除用)など、当該レコードを変更する可能性があるボタン、スクリプトは[cntLockId]に他ユーザのIDがある場合は、実行出来ないように制御する。

【編集ボタンによるFileMakerライクなロック】

[cntLockId]と同じGet(持続ID)を持つユーザのみが編集可となり、確定ボタンが完了すると[cntLockId][cntLockTime][cntLockAC]はnullとなり、他のユーザも編集可能となる。


注:
サーバのRemote Desktop Service を介して複数人でFileMakerを使用する場合、Get(持続ID)は重複すると思われる。この場合、他の方法で個別IDを取得すること。

(土屋)

2012-06-08

SQL関連記事と『売上猫くん on MySQL』開発日記の一覧








【FileMaker/MySQL環境での大容量データ取扱(英語のみ/動画による実例あり)】
Big Table Handling Model in FileMaker/MySQL Environment ― Tentative one
FileMaker vs Access 実行速度比較検証


【FMEasy在庫 on MySQL関連】
『FMEasy在庫』 のバックエンドを MySQL に変える (1) ― 概要
『FMEasy在庫』 のバックエンドを MySQL に変える (2) ― 在庫1
 


【その他のFileMaker/MySQL関連】
 ファイル起動時にFileMakerからMySQLに投げられるクエリ



【MySQL Workbench関連】
MySQL Workbench の EER モデリングツールでリレーションシップ検証 1 (Identifying と Non identifying)
MySQL Workbench の EER モデリングツールでリレーションシップ検証 2 (外部キー制約の種類と動作)

MySQL Workbench の EER モデリングツールでリレーションシップ検証 3 (リレーションシップアイコンの種類と使い方)
 



【売上猫くん開発日記 ― 番外編】
番外1 -全データベース削除→リストア
番外2 - MySQLミラーサイト
番外3 - 0を書き込みできない
番外4 - mysqldump で文字化け?
番外5 - ポータルで検索できない
番外6 - リモートのログを mysqlbinlog できない
番外7 - FileMaker内にMySQLの一般ログを表示する
番外8 - insert...select構文とODBC
番外9 - 外部キー制約設定でのたうちまわる
番外10 - 開発再開
番外11 - 外部キー ってさぁ… orz
番外12 - トリガの制約
番外13 - MySQL Workbenchの憂鬱(ほぼ私的メモ)
番外14 - テーブル毎に権限を設定する(ほぼ私的メモ)
番外15 - 再び権限(私的メモ)
番外16 - FMで大きなSQLテーブルは扱えるのか? ― その1
番外17 - FMで大きなSQLテーブルは扱えるのか? ― その2
番外18 - FMで大きなSQLテーブルは扱えるのか? ― その3
番外19 - FMで大きなSQLテーブルは扱えるのか? ― その4
番外20 - ウィンドウ内容の再表示ステップ実行時のクエリ
番外21 - βリリースしまつた
番外22 -SQL SECURITY の DEFINER/INVOKER指定
番外23 - FileMaker vs Access ~ 実行速度編 ~
番外24 - MySQL 5.5は使用できるのか?
番外25 - 行ロックについて


【売上猫くん開発日記 ― 本篇】(←メインになる筈が、見捨てられた哀れな本編)
1 (題目無)
2 - 開発環境
3 - FMからストアド、トリガ



2012-06-05

『売上猫くん on MySQL』開発日記 - 番外24 - MySQL 5.5は使用できるのか?

FileMakerとMySQL 5.0/5.1で開発してきた人へ:

『売上猫くん on MySQL R5.0β』は、FileMaker 11(FM11)/MySQL 5.1で開発した。 そのDBダンプをMySQL5.5上 にリストアして、FM11フロントエンド(NekoApp.fp7)からアクセスしようとすると、以下のような状況となり、アクセスできない。



このNekoApp.fp7をFileMaker 12(FM12)でNekoApp.fmp12に変換し、MySQL5.5にアクセスするとどうか?



と、さらに悲惨なこととなる。


NekoApp.fp7のリレーションシップ画面を開いてみると、下図のように一見すると正しくテーブルは認識されているようだが、TOをダブルクリックしてみるとTOとテーブルのリンクが消失していて、テーブルを指定し直す必要がある。


また、その指定し直しの過程でリレーションシップが飛んでしまったりもする。 TOとリレーションシップをすべて再設定・確認するだけども大変な作業になるし、検証作業も含めると… 膨大な作業になる。


注:
  • 使用しているODBCのバージョンは、5.1.11。 
  • FM社が公式サポートするMySQLは現時点でMy SQL 5.1 Community Editionのみ。
  • MySQL5.1を介さず、最初からFM11/12とMySQL5.5でリレーションシップ(TO)を作成しておけば、とりあえずは動作するようである(要検証)。

2012-06-01

簡単? FileMakerで在庫管理(2) ―― 繰越処理の考え方

 今回は、繰越処理に伴う在庫算出について考えていきましょう。 在庫算出の基本については、以下の記事をご覧ください。

 簡単? FileMakerで在庫管理(1) ―― 在庫算出の基本


繰越処理の考え方


 入出庫のレコードが増えてくると、在庫算出時に合計する入出庫明細レコードが膨大になり、処理速度が低下します。
 そこで、在庫数の繰越処理を行うことによって、在庫算出処理を行うことにより、在庫数算出を高速化する必要があります。
 
 たとえば、商品Aの2011年6月~2012年5月の入出庫明細データが10万件あったとします。
 2012年5月31日時点の商品Aの在庫を算出しようとして、入出庫明細レコードを10万件を対象に、Sum(入庫明細::入庫数)-Sum(出庫明細::出庫数) をやっていては、処理時間が膨大になってしまいますが、繰越処理を実行することによって2012年4月末時点の商品Aの在庫数を商品テーブルに保管しておき、5月1日~5/31の入出庫明細レコードのみをSumの対象となるようにリレーションを組めば、Sumの対象となるデータは、単純試算では10分の1以下となります。

 次に在庫算出の計算式を、以下のように繰越処理を行った場合と、行ってない場合とでは、在庫算出の計算式が違ってきます。

A式: 導入時在庫数+(4/25以前の入庫計)-(4/25以前の出庫計)

B式: 繰越処理日≦在庫基準日の場合の在庫算出式
繰越在庫数+(4/1~4/25の入庫計)-(4/1~4/25の出庫計)


C式: 繰越処理日<在庫基準日の場合の在庫算出式
  導入時在庫数+(2/28以前の入庫計)-(2/28以前の出庫計)

 要はA、B、Cの式をCase分けして、ひとつにまとめる必要があるわけです。



繰越処理と制御


 さて、繰越処理で考えておかなければいけない重要なことが一つあります。それは、繰越処理日(上記例では3/31)以前のデータ、在庫に関していえば、3/31以前の入出庫レコードの出庫日と入庫日、出庫数と入庫数を変更不可にしておく必要があります。また、3/31以前の同レコードは削除させてはならないし、繰越処理日以前の入出庫日を持つ同レコードは作成させてもいけません。 

 その理由は、[繰越在庫数]との整合性がなくなってしまうからです。

やがて訪れるデータ削除の時期について:
 長期間使用するシステムでは、繰越処理を行ってもレコードはどんどん蓄積されていきます。当社が開発・保守を担うシステムでは百数十万件の入出明細データを持つテーブルがありますが、ほぼ定期的にデータ削除を行っています。小社では、FileMaker のテーブルの最大レコード蓄積数は200~300百万件を一つの目安としていますが、データの削除は、システム仕様、実行速度要求、保持データ数要求、バックアップポリシー等の諸事情を勘案し、システムが安定動作することを大前提に実行してください。一般ユーザがデータ削除を行う場合は、一括データ削除機能も必要になります。
 また、削除したデータを照会したい、といった要望も必ずといっていいほどユーザより提示されるので、できれば過去データの照会についても予め考慮してシステム設計を行います。


在庫管理は簡単か?


 残念ながら答えは NO です
 システム的には、繰越処理とそれに伴う伝票制御、旧データ削除時の処理を考慮せざるを得ず、在庫管理システムを作るのはやはり簡単ではない、というのが結論になります。

 また、繰越処理関連を適正に実装できたとしても、1カ月に同一商品の取引が数百回以上あるような業務では在庫算出処理の遅延も予想され、別の在庫算出手法(拙稿の「FileMaker V10による在庫管理、一考」の123を参照)の採用も選択肢に入れなければならないでしょう。



土屋

2012-05-27

簡単? FileMakerで在庫管理(1) ―― 在庫算出の基本

 本稿は2012年5月に投稿されたものです。2018年2月現在、最新の FileMaker のバージョンは 16 となっていますが、本稿及び続稿で記述した在庫に関するの設計手法は現在も有効と思われます。
 ただ、iBeacon/EddyStone の登場等や、記事に気になる点があったため、今回、加筆修正することにしました。また、SQLを使った在庫の繰越処理などについても加筆したいと思っているのですが、これについては別の機会にしたいと思います。
(土屋企画)

 本稿では FileMaker を使用した在庫算出の方法について考えます。ただ本論に入る前に、在庫算出の3つの手法を大雑把に見てみます。それぞれの手法に便宜的に名前を付けていますが、これらは筆者が勝手に名付けたもので、社会、業界で一般的に利用されている名称ではありませんので、他所で「入出庫小計差分法を採用したいのですが…」とか言っても、相手の方は「???」となるでしょう。

在庫算出3つの手法

入出庫小計差分法

  この手法は当方の様々な在庫管理システムで使用している方法で、FileMaker で在庫算出する際の一般的な手法と思われます。いつの時点の在庫を知りたいのか(以下[在庫基準日])を決め、その時点までの入庫数計と出庫数計を計算、その差分が在庫となります。下図の4/30時点の在庫は、4/30迄の入庫計=20と出庫計=6の差分で[在庫]=14となります。
 Excelでは、出庫数の横に在庫列を作成して「D4+B5-C5」などとすれば簡単に在庫が求められますが、リレーショナルデータベースではそうした計算はできません。なぜならリレーションの無い行同士の演算はできないからです。無理に外部キーを振ったり、スクリプトのループで加減演算しても、結局は破綻します。
この方法は比較的単純ですが、特定の商品が頻繁に取引されるようなシステムでは、在庫算出処理に想定外の時間を要する可能性があります。

在庫マスタ逐次書換法

本手法は下図のように入出庫に変動があった場合、在庫マスタの[在庫]フィールドを即時更新する、というものです。下図を例に説明すると、3/31に[入庫数]=10を入力してコミットすると、在庫マスタテーブルの商品Aの[在庫]は即刻10に更新され、4/1に[出庫数]=1を入力すると[在庫]は9に即更新されます。
この方法は、入出庫伝票更新時に在庫マスタを即更新するため、その後発生する在庫照会や在庫表印刷の処理では各商品の在庫算出を行うことはなく、高速です。ただ、実装方法が難しいこと、上述の在庫基準日を指定できないこと、入庫日と出庫日には未来の日付を入力できないことなど、デメリットは少なからずあります。 ただ、同一商品の入出庫が頻繁に発生し、リアルタイムに在庫を把握する必要がある業態では、この手法を採用することが多いでしょう。実は2009年に本手法に関する投稿とサンプルファイル(現在リンク切れ)を公開しています。興味があるかたはこちらをどうぞ。

ビーコン信号カウント法

近年リリースされた iBeacon/EddyStone(以下、ビーコン) は少ない電力(電池)でユニークな値(UUID/UID)を含む信号を数カ月~数年、0m~100mほどの範囲で発信する装置です。
土屋企画で使用するビーコン ― 左の小さいタグ型ビーコンは 40mm×28mm 
このビーコンを製品に取り付け、その信号を取得・処理することでほぼリアルタイムに商品の在庫を把握することができます。以下のシステム図は 、Raspberry Pi と呼ばれる超小型Linux機(価格は約3000円/台)を広い倉庫内に万遍なく配置、ビーコン信号を漏れなく取得し、データベースの在庫テーブルを更新するというものです。
 入出庫システムからは独立して、在庫数の把握が可能となります。

本手法はビーコンが高価(500円~数千円~)であること、取り付けが不能・不向きな製品があること、電池に寿命があり交換が必要なこと等、ビーコン特有の問題があります。ビーコンについてはこちらを参照してください。


在庫算出の基本

さて、それでは上述の「入出庫小計差分法」について以下そのしくみを見ていきます。

 「2012年6月20日時点の在庫」というような特定時点(在庫基準日)の在庫数を算出するために、以下のようなTOG(テーブル・オカレンス・グループ)を作成してみます。


 商品マスタと出庫明細と入庫明細をリレートするだけですのでシンプルですね。
実際アプリケーションでは、出庫明細や入庫明細を格納するための出庫と入庫のテーブルが必要ですが、ここでは省略します。
 以下は上記リレーション |×| で示された部分のリレーション編集イメージです。


 [g在庫基準日]は日付のグローバルフィールドという特殊なフィールドで、詳しくは FileMaker のマニュアルを参照してください。ユーザはこのフィールドで在庫算出の起点となる日付 ― 在庫基準日 を指定します。

 そして、こちらが在庫算出用フィールド=[c在庫数]の計算式です。

繰越在庫数- Sum(出庫明細_商品::数量) + Sum(入庫明細_商品::数量)


 システム導入時、[繰越在庫数]には各商品の導入時点での在庫数を入力します。導入時、在庫が無い商品については「0」を入力しておきます。
 上記の計算式もシンプルで、[繰越在庫数](=ここでは導入時点の在庫数)から[g在庫基準日]以前に出庫した商品数量を差し引いて、さらに[g在庫基準日]以前に入庫した商品数量を加え、在庫を算出しているだけです。
 [g在庫基準日]より後の日付の入出庫が[c在庫数]の計算式の対象とならないのは、上図「在庫算出TOG」のリレーションで「≧」によりそのように定義されているからです。
注:
  1. 本稿読者で「出庫明細/入庫明細テーブルに[出庫日]/[入庫日]があるのはおかしいではないか。  本来、この二つのフィールドは出庫ヘッダ/入庫ヘッダテーブルにあるべきで、冗長で正規化されていないではないか?」と考えた方 、 御尤もです。ただ、FileMaker 内蔵DBを使用し、在庫算出基準日を任意に指定可という仕様を前提にした場合、正規化を崩しても明細に日付を持たせるのが良い、というのが小社の知見です。
  2. 但し、ExecuteSQL 関数によるSQLクエリを使用して出庫と出庫明細、入庫と入庫明細を結合(JOIN)すれば、[出庫日]/[入庫日]がそれぞれの明細テーブルに存在しなくても、在庫数を取得することができます。ただ、FileMaker の結合は実行速度が非常に遅くなることがあるので、留意が必要です。この手法についてはこちらを参考にしてください。
  3. 上記1の通りに設計する場合、出庫ヘッダ/入庫ヘッダの[出庫日]/[入庫日]と、出庫明細/入庫明細テーブルの[出庫日]/[入庫日]は常に一致するようにシステム的に保証しなければなりません。ユーザがヘッダ部の[出庫日]/[入庫日]を変更することは頻繁にあるので、スクリプトトリガを使用して、うまく制御してください。

 上記の注2 の部分が少し面倒ですが、ここまでは比較的簡単にアプリを作成できると思います。

 ただ、入出庫レコードが数千、数万と増えるに従い、在庫(c在庫数)の表示には時間がかかるようになります。在庫算出処理の時間を短くするためには、繰越処理を行い、[c在庫数]の計算対象となる入出庫レコードを減らす必要があります。 繰越処理とそれに伴う処理については、 簡単? FileMakerで在庫管理(2)―― 繰越処理の考え方 をご覧ください。

TOG(テーブル・オカレンス・グループ) とは?

FileMaker Pro 7 以降に導入されたリレーションシップグラフでは、テーブルを別名、または同一名で定義して配置できます。
 たとえば「商品」というテーブルは、リレーションシップグラフ上では「商品Table1」、「商品テーブル」、「商品」など自由に名前をつけて配置したり、同一のテーブルを別名で複数配置したりできます。

 リレーションシップシップウィンドウに配置されたテーブルは、単に”テーブル”と呼ばれたり、テーブルのエイリアスあるいはTO(テーブル・オカレンス)と呼ばれることもあります。

 FileMaker界隈 では TO という呼び名が一般的になってきているようです。また、処理別やレイアウト別に TO をグループ化したものを TOG (テーブル・オカレンス・グループ)と呼んでいます。


 以下の動画では『FMEasy在庫 IWP/WD 1.5』という製品を使用し、在庫算出に関して説明しています。




 その他の在庫関連記事を読む

(土屋)

2012-03-30

FileMaker の分離モデル - 2

 前回、分離モデルのメリットは以下の4点と書いた。

  1. 仕様変更時のダウンタイムを最小限にする
  2. 同一システムが複数の拠点やユーザにより運用される場合、アップグレードが容易
  3. データベースに重大な損傷が発生した場合、データファイルのみ再構築すれば良い
  4. 公開マスタ(郵便番号、宅配便仕訳コード等)の更新・入替が容易
 2.は、多数のユーザが運用するアプリケーション、パッケージやネットからダウンロードするようなアプリケーションで大いに役立つ。

今日は上記1.について。

 FileMaker Ver6以前は1ファイルに1テーブルしか付属させることができず、更にそのファイル毎にリレーション、スクリプト、値一覧、アクセス権限といったオブジェクトも作成・管理をしていた。

 小社のある得意先は、FileMaker Ver5.5のデータベースを現在も運用しており、そのファイル数は約60、そのうち数千~200万弱のレコードを保持するファイルが数十ある。 FileMaker Ver3で開発を初め、納品後に仕様変更と追加を十数年にわたり重ねてきた。 FileMakerのバージョンが上がりアップグレードを行いたいのは山々であったが、規模が大きくなり過ぎアップグレードには多くの費用がかかるため、今日まで旧システムを延命してきている。 

 さて、このようなシステムで仕様変更が発生し、その変更が多くのファイルに及んだ場合、どうやって納品するか? システム屋は大変である。 まず最初に考えられるのは、開発を行ったデータベース(開発版)のクローン(ファイルのデータ無コピー)を作成し、そのクローンに運用中のデータベース(運用版)の全データを取り込むことが考えられる。この方法は単純だが、レコード数が数十万を超えるファイルが多くそのファイルに仕様変更が含まれる場合、非常にデータ移行作業に時間がかかり、システムのダウンタイムも長くなる。 また、作業中のミス、例えばデータ取込ミスや、取込後の主キーの設定漏れ、などの重大なリスクも抱えている。

 次に考えられるのが、仕様変更があったファイルを、a.レコード数が少ないファイル、b.仕様変更が多いファイル、3.仕様変更が少なくデータが多いファイルに分け、a.とb.については上述のクローンへのデータ取り込みで、c.については、運用版のファイルに開発版で行ったのと同じ変更を直接入れる、という方法である。 この方法は「データの多いファイルに変更が少ない」場合、システムのダウンタイムを大幅に減らせる可能性があるが、逆に作業のリスクは増すことになる。つまり、FileMaker Ver6以前で規模の大きな仕様変更が発生すると、簡単な納品方法はなかったのである。

 もし、上記のような仕様もデータも大規模なシステムが、データとアプリケーションに厳密に分離されているシステムであったらどうだろうか。 仕様変更がデータ側、つまりテーブルに及ばないのであれば、アプリケーションファイルを入れ替えるだけ、ダウンタイムはせいぜい1分前後となる。 仕様変更が複数のテーブルに及んだり、テーブルの新規追加があったとしても、一部フィールドを追加し、新規テーブルをコピーすればよいだけである。この作業はオンラインでバックアップを取った後であればサーバを落とすことなく実行可能である。 データファイルの作業を行った後、アプリケーションファイルを入れ替えれば作業終了である。

 ダウンタイムを最小限にしたい、“落せないシステム”において、分離モデルは特に有用である。

(土屋)



【関連リンク】
分離モデルにおけるSUM/ExcecuteSQL関数の問題と対策
土屋企画の講習 ― 分離モデルに基づく請求書システムを作る(対象者:中級、4時間×2日)
FileMaker の分離モデル



【分離モデルに基づく在庫管理テンプレートのご案内】
分離モデルに基づき開発された在庫管理システムテンプレート「FMEasy在庫」の紹介記事は→こちら
「FMEasy在庫」フリー版/開発版のダウンロードは→こちら

【FMEasy在庫 の画面】

(2012/12/20追記)

2012-03-21

Hyper-V のゲスト OS の BIOS 不良で泣かされる

Hyper-V てはゲスト OS を複数運用できるため、今となっては弊社の業務に欠かせない存在ですが、当方のブログでもたびたび記事を書いているとおり、過去にも色々とトラブルに泣かされていることも確かです。

 さて、今回も月曜日の朝からゲスト OS が起動して来ないというトラブルに見舞われました。
 Hyper-V マネージャ画面を見ると、「仮想マシンの構成記憶域に接続できません」というエラーメッセージが表示されています。しかも状況は「重大」のようです。



 試しに起動してみると、以下のようなエラーメッセージが返されました。



 
 ゲスト OS の設定を確認してみると、BIOS の読み込みに失敗したとあります。
 BIOS 設定に何らかの障害が発生し、起動不能になった模様です。



 ネットを調べ回ったところ、仮想マシンを削除(仮想ディスクはそのまま残すこと)し、再度追加することで解決するとあったので試したところ、復活しました。

 ただし、システムの状態によっては Windows ライセンス認証がもう一度必要になったり、IP アドレス設定が丸々飛んだりしたりするので、その辺の微調整は必要になるかもしれません。

 ただ、今回のように突然ゲスト OS が起動しなくなる可能性がありますので、同じように BIOS による起動トラブルが発生した場合は、今回の方法をダメ元で試してみるのも一つの方法かもしれません(ただし、自己責任ということでお願いします)

【備忘録】 Team Foundation Server で公開されているソースを取得する方法

Team Foundation Server で共有されているソースにアクセスし、クライアントコンピュータで使用するまでの手順をまとめてみました。

 本記事は、Team Foundation Server がインストール済みであり、かつソースが公開設定されていることが前提になっていますので、Team Foundation Server 側の設定については省略してあります。

 なお、ユーザインタフェースは英語表記になっていますが、一応注釈を付けておりますので、日本語のメニューと読み替えてください。
1. Visual Studio 2010 を起動し、トップ画面の一番上に表示される Connect to Team Foundation Server (Team Foundation Server に接続) をクリックするか、メニューバーより、「Team」→「Connect to Team Foundation Server」を選択します。



2. Connect to Team Project (チームプロジェクトに接続)というダイアログが表示されます。
 初回起動時は接続可能な Team Foundation Server が未登録の状態ですので、サーバを登録する必要があります。
 “Servers...”をクリックします。


3. Add/Remove Team Foundation Server (Team Foundation Server の追加と削除)というダイアログが表示されますので、“Add...”(追加)をクリックします。



4. Team Foundation Server がインストールされているサーバの URL、または Team Foundation Server の名前を入力し、“OK” をクリックします。



5. 上記で登録した Team Foundation Server への接続が行われ、Connect to Team Project (チームプロジェクトに接続) というダイアログに、利用可能なチームプロジェクトの一覧が表示されます。

 特定のプロジェクトを選択することも、すべてのプロジェクトを選択することも可能です。
 以下は、すべてを選択した状態を示しています。
 選択が終わったら、“Connect” (接続)ボタンをクリックします。



6. Team Explorer (チームエクスプローラ)が表示されますので、その中から一番下の Source Control (ソースコントロール)をダブルクリックします。



7. Source Control Explorer (ソースコントロールエクスプローラー)が開きます。
 ソースを取得したいプロジェクトを右クリックし、表示されるサブメニューより、Get Latest Version (最新バージョンを取得)を選択します。



8. Map (マップ)というダイアログが表示されますので、ローカルコピーを保存するためのフォルダを指定します。

 以下では、ローカルのドキュメントフォルダに NekoTFS というプロジェクトフォルダを指定しています。
 “Map” をクリックすると、Team Foundation Server から現在の最新バージョンのソースがコピーされるとともにマッピング設定が行われます。



 これで Team Foundation Server にアクセスしながらソース管理を行うための下準備が整いました。

2012-03-09

FileMaker の分離モデル

 今日はお問い合わせ上昇傾向のFileMaker分離モデルについて。 小社ではFileMakerの分離モデル講習をおこなっており、先日もその講習会を開かせて頂いた。

 当方がFileMaker 7以降で開発したパッケージ製品、及び受託開発システムは、必ずほんとんど分離モデルを採用している。 なぜか? その理由、つまり分離モデルのメリットは以下の4点。

  1. 仕様変更時のダウンタイムを最小限にする
  2. 同一システムが複数の拠点やユーザにより運用される場合、アップグレードが容易
  3. データベースに重大な損傷が発生した場合、データファイルのみ再構築すれば良い
  4. 公開マスタ(郵便番号、宅配便仕訳コード等)の更新・入替が容易
仕様変更が予想される業務システムは、仕様変更の度にシステムを長時間ダウンさせるわけにはいかず、かといってシステム担当者( or 業者)に休日・深夜労働させるのは酷な(だけではなくミスの原因!)ので、1.は特に重要。
 アプリファイルだけの仕様変更であれば、1ファイル入替だけですべてのアップグレード作業が完了。 データファイルに変更があった場合でも、ほとんどの場合は、非常に短い時間でアップグレードを完了させることができる。 
 その為には、単純にアプリとデータのファイルに分けるだけではなく、データファイル側ではビジネスロジック(フィールドオプション/計算式、リレーション、スクリプト)を組み込まないことがキモとなる。

 今回の受講者のはdBaseで長く開発してこられ、事前のFMの勉強もバッチリだったため、ER図と資料を見ながら サンプルアプリ(請求書発行システム)を 一人でほぼ作れるレベルだったので、8時間の講習のうち多くの時間を分離モデルの説明とQ&Aにあてることができた。 これをステップに過去のシステムに劣らない立派なシステムを構築して頂きたい。

(土屋)


【関連リンク】
土屋企画の講習 ― 分離モデルに基づく請求書システムを作る(対象者:中級、4時間×2日)
FileMaker の分離モデル - 2


【分離モデルに基づく在庫管理テンプレート】
分離モデルに基づき開発された在庫管理システムテンプレート「FMEasy在庫」の紹介記事は→こちら
「FMEasy在庫」フリー版/開発版のダウンロードは→こちら

【FMEasy在庫 の画面】

(2012/12/20追記)