修改的预订树:选择特定类型的顶级元素

时间:2013-04-15 10:48:29

标签: mysql database preorder

我使用修改后的预订树在我​​的应用程序中将GEO位置存储在单个表LOC_TABLE中。例如,子树的例子希腊看起来像这样:

+-------+---------------+-----+-----+------+
| ID    | NAME          | LFT | RGT | TYPE |
+-------+---------------+-----+-----+------+
|    10 | Greece        | 100 | 200 |   3  |
|    20 | Crete Isl.    | 120 | 140 |   4  |
|    25 | Crete-Vamos   | 121 | 122 |   4  |
|    26 | Crete-Rethymno| 123 | 124 |   4  |
 ....
+-------+---------------+-----+-----+------+

TYPE列用于存储位置类型(3 - 国家/地区,4 - 城市)。如您所见,克里特岛被存储为城市,其中包含其他城市(例如VamosRethymno)作为其子女。

我需要执行两种类型的查询:

1)获取特定父级下特定类型的所有位置。

2)获取特定父级下特定类型的所有顶级位置:对于提供的位置示例,在查询希腊境内的城市时应返回Crete Isl.,因为Crete Isl.没有父类型城市,而城市VamosRethymno拥有城市类型的父级 - Crete Isl.

在每种情况下执行的最快查询是什么?

对于第一种情况,我考虑使用两个查询(首先,获取希腊的LFT和RGT,第二个获取类型= 4的所有位置,具有适当的LFT和RGT)或使用某种类型的连接来获取所有位置一步到位哪种方法最好?

对于第二种情况,我目前没有任何合适的想法。我尝试过简单的子选择:

select loc.* from LOC_TABLE loc 
where 4 not in 
(select TYPE from LOC_TABLE p 
    where p.lft < loc.lft AND p.rgt > loc.rgt) 
AND loc.LFT > 100 AND loc.RGT < 200;

但它太长了。

我不介意添加更多列并使用一些值填充它们,这将有助于加快这两种类型的查询。但我需要快速获取数据。

感谢。

2 个答案:

答案 0 :(得分:1)

对于ID给出:id的特定记录的城市和后代的所有记录,请使用

SELECT descendant.ID, descendant.NAME, descendant.TYPE 
FROM LOC_TABLE location
INNER JOIN LOC_TABLE descendant
    ON descendant.LFT > location.LFT AND descendant.RGT < location.RGT
WHERE location.ID = :id AND TYPE = 4

对于ID :id givien SELECT child.ID, child.NAME, child.TYPE FROM LOC_TABLE location INNER JOIN LOC_TABLE child ON child.LFT > location.LFT AND child.RGT < location.RGT LEFT OUTER JOIN LOC_TABLE intermediate ON intermediate.LFT < child.LFT AND intermediate.RGT > child.RGT AND intermediate.LFT > location.LFT AND intermediate.RGT < location.RGT WHERE location.ID = :id AND child.TYPE = 4 AND intermediate.ID IS NULL 的记录的城市和子项的所有记录,请使用

LEFT OUTER JOIN

intermediate.ID IS NULL以及条件child会删除那些location记录,其中child的后代是{{1}}的祖先。< / p>

答案 1 :(得分:1)

我会尝试这样的事情: -

SELECT b.*
FROM LOC_TABLE a
INNER JOIN LOC_TABLE b
ON a.LFT < b.LFT AND a.RGT > b.RGT
WHERE a.ID = 10
AND b.TYPE = 4

简单加入。

对于你的第二个问题,也许是这样的。找到父级,然后从中找到正确类型下面的所有记录。找到这个孩子的同一类型的父母。如果找到一个,则忽略。

SELECT b.*
FROM LOC_TABLE a
INNER JOIN LOC_TABLE b ON a.LFT < b.LFT AND a.RGT > b.RGT
LEFT JOIN LOC_TABLE c ON c.LFT > b.LFT AND c.RGT < b.RGT AND b.TYPE = c.TYPE
WHERE a.ID = 10
AND b.TYPE = 4
AND c.ID IS NULL