最近悩んでいた問題から。
以下のような性質を持つシステムを考えます。
- システムはノードから構成される。
- 各ノードは内部状態を持つ。
- ノードはネットワークも持つ。ただし、ループはないものとする。
- この時に、ノードやネットワークの変化を検出したい。
- 子ノードが変化したときも親ノードの状態変化として検出したい。
図で時間は上から下に流れおり、t=t1ではネットワークの変化が、t=t2ではAノードの変化が検出されています。
普通に考えると、SQL のテーブルは以下のようになるかと思います。
CREATE TABLE node (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(1024) NOT NULL;
CREATE TABLE content (id INTEGER PRIMARY KEY NOT NULL, node_id INTEGER NOT NULL, content VARCHAR(1024) NOT NULL);
CREATE TABLE graph (id INTEGER PRIMARY KEY NOT NULL, parent_id INTEGER NOT NULL, child_id INTEGER NOT NULL);
CREATE TABLE node_log (id INTEGER PRIMARY KEY NOT NULL, contents_id INTEGER, state INTEGER DEFAULT 1, created_at DATETIME);
CREATE TABLE graph_log (id INTEGER PRIMARY KEY NOT NULL, graph_id INTEGER, state INTEGER DEFAULT 1, created_at DATETIME);
しかし、この方法には2つの問題があります。
- 変化を検出するのに、node_log, graph_log 2つのテーブルを見る必要がある。
- node, graphテーブルの状態変化がすぐには分からない。
まず、1つのテーブルで済むようにするのに、一番安易な回答は2つのテーブルの OR をとったテーブルを作ることでしょう。
CREATE TABLE system_log (id INTEGER PRIMARY KEY NOT NULL, content_id INTEGER, graph_id INTEGER, state INTEGER DEFAULT 1, created_at DATETIME);
2番目の問題を解決するには LEFT JOIN を使用します。
例えば、現在のノード状態を算出する SQL は以下のようになります。
SELECT status FROM system_log LEFT JOIN content c ON c.id=system_log.content_id
LEFT JOIN node n0 ON n0.id=c.node_id
LEFT JOIN graph g ON g.id=system_log.graph_id
LEFT JOIN node n1 ON g.child_id=n1.id
LEFT JOIN node n2 ON g.parent_id=n2.id
WHERE n0.id=:node_id AND n1.parent_id=n0.id AND n2.child_id=n0.id
ORDER BY id DESC
LIMIT 1;
ノードやグラフに変化があったときは status > 1 として system_log に書き込むだけで済みます。
コメントを残す