2012-03-04 3 views
1

にもかかわらず、私は現在、これらのカラムを持つテーブルを持っている検索(高速):行継承

id (INT) 
parent_id (INT) 
col0 
col1 
col2 

例として、このテーブルに保存され、次のエントリがある:

1  NULL abc  def  NULL 
2  1  test NULL NULL 
3  1  NULL NULL xyz 

すぐ私はそれらを指している行Bを持っていないすべての行Aを検索したい(B.parent_id = A.id)。さらに、行の値は現在の行に存在する値でなければならず、NULLがある場合は、親の値を考慮する必要があります。私の要件を説明するために

私はいくつかの例を表示したい:

SEARCH(col0=test) => #2 (#1 has some children, #3.col0 = abc (inherited from #1)) 
SEARCH(col1=def) => #2, #3 (#1 has some children) 
SEARCH(col2=xyz) => #3 (#1 has some children, #2.col2 = NULL (inherited from #1)) 

はMySQLで、このような検索を実装する方法を誰もが知っていますか?

+0

いくつかの例に行と目的の結果セットを与えます。 –

答えて

2
SELECT 
# if first table has no value, use parent table 
IF(t1.col0, t1.col0, t2.col0) as virtcol0, 
IF(t1.col1, t1.col1, t2.col1) as virtcol1, 
IF(t1.col2, t1.col2, t2.col2) as virtcol2 
FROM table as t1 
LEFT JOIN table as t2 ON t1.parent_id = t2.id 
LEFT JOIN table as t3 ON t1.id = t3.parent_id 
# t3 would be children of t1. We don't want t1 to procreate. :) 
WHERE t3.id IS NULL 
# Your actual search goes here: 
AND virtcol0/1/2 = whatever 

高速?いいえ、あなたがこれから得ることができる最高のインデックスの使用は、id/parent_idの結合です。

多くのデータと小さな結果セットがある場合は、インデックスで列を直接照会して、別のクエリで親と子のチェックを実行できます。それは、巨大なテーブルで上記のクエリを実行するよりもはるかに高速です。

+1

結果に数値ゼロまたは空の文字列を含めることができる場合は、IFをIS NOT NULLに調整することができます。 – Someone

+1

...または['COALESCE()'](http://dev.mysql.com/doc/refman/5.6/en/comparison-operators.html#function_coalesce)ですらあります。 –

+0

前にそのことを聞いたことはありません。非常に便利です! :) – Someone

2

きれいな解決策は、おそらく親と子の列を持つビューを作成することですがマージされた:それは通常のテーブルであるかのように

CREATE VIEW foo 
AS SELECT 
    c.id AS id, 
    COALESCE(c.col0, p.col0) AS col0, 
    COALESCE(c.col1, p.col1) AS col1, 
    COALESCE(c.col2, p.col2) AS col2 
FROM table AS c 
    LEFT JOIN table AS p ON p.id = c.parent_id 
WHERE NOT EXISTS 
    (SELECT * FROM table AS x WHERE c.id = x.parent_id) 

は、その後、あなたは、このビューに対してクエリを書くことができます。

しかし、Mantriurノートでは、これはでなく、と非常に効率的です。テーブルが頻繁に変更されない場合は、CREATE VIEWの代わりにCREATE TABLE ... SELECTを使用して、マージされたデータを含む実際のテーブルを作成し、インデックスを作成して効率的にクエリできます。ただし、このような表は、ビューの動作と同じように元の表の変更を追跡しません。

原則として、トリガー(またはアプリケーションロジック)を使用して、元のテーブルの変更に合わせてマージされたテーブルをリアルタイムで更新できますが、これは簡単に複雑になり、エラーが発生しやすくなります。残念ながら、他のいくつかのRDBMSがmaterialized viewsをサポートしていますが、これは本質的にこれを自動的に行う方法ですが、現在MySQLはそうではありません。

(まあ、いないネイティブに、とにかく。私はそれを自分で試していませんが、は、Flexviewsあります。)