假設(shè)你系統(tǒng)里數(shù)據(jù)庫請求的函數(shù)是 pdo_query (你自己根據(jù)情況調(diào)整),表名是tblcate
創(chuàng)新互聯(lián)公司堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站建設(shè)、網(wǎng)站設(shè)計、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的繁昌網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
另外,這段代碼使用到了array_column函數(shù),該函數(shù)從php5.5起才有,如果你的版本較低,要找一個兼容函數(shù)放到函數(shù)庫里(官方文檔評論中就有實現(xiàn))
以下是代碼文本 如果復(fù)制過去出現(xiàn)T_VARIABLE錯誤,就是代碼中字符被系統(tǒng)混掉了,你要重新手打一下
//這里根據(jù)你的意思,應(yīng)該是選出沒有下級的節(jié)點,如果需要全部或其它的,你根據(jù)情況修改,不影響后面的其它操作
$selectedNodes = pdo_query("select * from tblcate where pid not in(select pid from tblcate)");
//選出全部節(jié)點
$allNodes =?pdo_query("select * from?tblcate ");
//將節(jié)點數(shù)據(jù)使用id索引,方便獲取
$allNodes = array_column($allNodes, NULL, 'id');
foreach($selectedNodes as $node){
$tree =?getParentNode($node['pid']);
//這里的$tree 是上級名稱拼起來的,不包含本級名稱,如要包含,在后面附加上就行了
$node['tree'] = implode(',',$tree);
}
unset($node);
var_export($selectedNodes?);
function getParentNode($pid){
global $allNodes;
$pnodes=[];
if($pid 0 isset($allNodes[$pid])){
$pNode =?$allNodes[$pid];
$pnodes[]= $pNode['name'];
$rnodes =?getParentNode($pNode['pid']);
if(!empty($rnodes)){
$pnodes = array_merge($pnodes,$rnodes);
}
}
return $pnodes;
}
你這種表結(jié)構(gòu)叫鄰接表,查詢的方式通過自連接。如
SELECT?t1.name?AS?lev1,?t2.name?as?lev2,?t3.name?as?lev3,?t4.name?as?lev4
FROM?Tbname?AS?t1
LEFT?JOIN?Tbname?AS?t2?ON?t2.pid?=?t1.id
LEFT?JOIN?Tbname?AS?t3?ON?t3.pid?=?t2.id
LEFT?JOIN?Tbname?AS?t4?ON?t4.pid?=?t3.id
WHERE?t1.name?=?'XXXX'
這種方法的主要局限是你需要為每層數(shù)據(jù)添加一個自連接,隨著層次的增加,自連接
變得越來越復(fù)雜,檢索的性能自然而然的也就下降了。當(dāng)然這種結(jié)構(gòu)在查詢前必須知道該節(jié)點所處的層級,否則無法確定自連接的深度。
鄰接表模型的局限性很大,用純SQL實現(xiàn)有一定的難度。不妨考慮其他模型,比如嵌套模型。
嵌套模型的基本結(jié)構(gòu)是樹型結(jié)構(gòu),SQL檢索比鄰接表要方便很多。
關(guān)于嵌套模型,PHPChina的第一期電子雜志PHPer也有過深入探討,請參考!
function get_category($id){
$str=array();
//$sql = "select * from biao where id=$id";查詢節(jié)點,自己寫吧
$result = array('id'=,'parent_id'=);//查詢結(jié)果一個數(shù)組格式
if($result){
$str = get_category($result['parent_id']);
$str[]=$result;
}
return $str;
}
}
調(diào)用get_category()就行了,$str第一個元素是節(jié)點本身,去掉就行了。
要構(gòu)建的無限分類的模型. 電子產(chǎn)品是最大的分類.家用電器 ,數(shù)碼產(chǎn)品是其子分類.可以看到子分類是被父分類包含起來的.每個分類都有左右 兩個節(jié)點編號分別是1、2、3.....
根據(jù)上面的圖mysql中建立表和插入數(shù)據(jù)
CREATE TABLE ?`product_categories` (
`id` MEDIUMINT( 8 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,`name` VARCHAR( 20 ) NOT NULL ,
`left_node` MEDIUMINT( 8 ) NOT NULL ,
`right_node` MEDIUMINT( 8 ) NOT NULL
) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci;INSERT INTO `product_categories` (`id`, `name`, `left_node`, `right_node`) VALUES(1, '電子產(chǎn)品', 1, 20),
(2, '家用電器', 2, 9),
(3, '電視機', 3, 4),
(4, '電冰箱', 5, 6),
(5, '空調(diào)', 7, 8),
(6, '數(shù)碼產(chǎn)品', 10, 19),
(7, '電腦', 11, 18),
(8, '臺式電腦', 12, 13),
(9, '筆記本電腦', 14, 15),
(10, '平板電腦', 16, 17);
表結(jié)構(gòu)如下:
下面是PHP的實例代碼:
1、獲取所有節(jié)點
?php
$pdo = new PDO(
'mysql:host=localhost;dbname=test',
'root',
''
);
$pdo-exec("SET NAMES UTF8");
$stmt = $pdo-prepare("SELECT c.name FROM product_categories as c, product_categories as pWHERE c.left_node BETWEEN p.left_node AND p.right_nodeAND p.name='電子產(chǎn)品' ORDER BY c.left_node");$stmt-execute();
$rs=$stmt-fetchAll(PDO::FETCH_ASSOC);
foreach($rs as $v){
echo $v['name'].'br /';
}
輸出:
電子產(chǎn)品
家用電器
電視機
電冰箱
空調(diào)
數(shù)碼產(chǎn)品
電腦
臺式電腦
筆記本電腦
平板電腦
2、 獲取某個父節(jié)點以及其所有子節(jié)點
?php
$pdo = new PDO(
'mysql:host=localhost;dbname=test',
'root',
''
);
$pdo-exec("SET NAMES UTF8");
$stmt = $pdo-prepare("SELECT c.name FROM product_categories as c, product_categories as pWHERE c.left_node BETWEEN p.left_node AND p.right_nodeAND p.name='數(shù)碼產(chǎn)品' ORDER BY c.left_node");$stmt-execute();
$rs=$stmt-fetchAll(PDO::FETCH_ASSOC);
foreach($rs as $v){
echo $v['name'].'br /';
}
輸出:
數(shù)碼產(chǎn)品
電腦
臺式電腦
筆記本電腦
平板電腦
3、獲取所有的葉子節(jié)點
?php
$pdo = new PDO(
'mysql:host=localhost;dbname=test',
'root',
''
);
$pdo-exec("SET NAMES UTF8");
$stmt = $pdo-prepare("SELECT name FROM product_categories where right_node-left_node=1");$stmt-execute();
$rs=$stmt-fetchAll(PDO::FETCH_ASSOC);
foreach($rs as $v){
echo $v['name'].'br /';
}
輸出:
電視機
電冰箱
空調(diào)
臺式電腦
筆記本電腦
平板電腦
4、獲取某個子節(jié)點及其所有父節(jié)點
?php
$pdo = new PDO(
'mysql:host=localhost;dbname=test',
'root',
''
);
$pdo-exec("SET NAMES UTF8");
$stmt = $pdo-prepare("SELECT p.name FROM product_categories AS c, product_categories AS p WHERE c.left_node BETWEEN p.left_node AND p.right_node AND c.name = '平板電腦' ORDER BY p.left_node");$stmt-execute();
$rs=$stmt-fetchAll(PDO::FETCH_ASSOC);
foreach($rs as $v){
echo $v['name'].'br /';
}
輸出:
電子產(chǎn)品
數(shù)碼產(chǎn)品
電腦
平板電腦
5、獲取所有節(jié)點極其所處的層級
?php
$pdo = new PDO(
'mysql:host=localhost;dbname=test',
'root',
''
);
$pdo-exec("SET NAMES UTF8");
$stmt = $pdo-prepare("SELECT c.name, (COUNT(p.name) - 1) AS level FROM product_categories AS c, product_categories AS p WHERE c.left_node BETWEEN p.left_node AND p.right_node GROUP BY c.name ORDER BY c.left_node");$stmt-execute();
$rs=$stmt-fetchAll(PDO::FETCH_ASSOC);
var_dump($rs);
echo 'br /';
foreach($rs as $v){
echo $v['name'].' level:'.$v['level'].'br /';}
輸出:
電子產(chǎn)品 level:0
家用電器 level:1
電視機 level:2
電冰箱 level:2
空調(diào) level:2
數(shù)碼產(chǎn)品 level:2
電腦 level:2
臺式電腦 level:3
筆記本電腦 level:3
平板電腦 level:3
6、獲取某個節(jié)點的層級
?php
$pdo = new PDO(
'mysql:host=localhost;dbname=test',
'root',
''
);
$pdo-exec("SET NAMES UTF8");
$stmt = $pdo-prepare("SELECT c.name, (COUNT(p.name) - 1) AS level FROM product_categories AS c, product_categories AS p WHERE c.left_node BETWEEN p.left_node AND p.right_node and c.name='平板電腦' GROUP BY c.name ORDER BY c.left_node");$stmt-execute();
$rs=$stmt-fetchAll(PDO::FETCH_ASSOC);
var_dump($rs);
echo 'br /';
foreach($rs as $v){
echo $v['name'].' level:'.$v['level'].'br /';}
輸出:
平板電腦 level:3
7、在某個節(jié)點后平行的插入一個節(jié)點
?php
$pdo = new PDO(
'mysql:host=localhost;dbname=test',
'root',
''
);
$pdo-exec("SET NAMES UTF8");
function addNode($left_node,$new_node){
global $pdo;
$stmt = $pdo-prepare("SELECT right_node FROM product_categories WHERE name = '$left_node'");$stmt-execute();
$rs=$stmt-fetch(PDO::FETCH_ASSOC);
$right_node=$rs['right_node'];
$pdo-exec("UPDATE product_categories SET right_node = right_node + 2 WHERE right_node $right_node");$pdo-exec("UPDATE product_categories SET left_node = left_node + 2 WHERE left_node $right_node");$pdo-exec("INSERT INTO product_categories(name, left_node, right_node) VALUES('$new_node', $right_node + 1, $right_node + 2)");}
addNode('家用電器','辦公用品');
完成之后表結(jié)構(gòu)如下:
8、刪除某個節(jié)點及其所有子節(jié)點
?php
$pdo = new PDO(
'mysql:host=localhost;dbname=test',
'root',
''
);
$pdo-exec("SET NAMES UTF8");
function deleteNode($node_name){
global $pdo;
$stmt = $pdo-prepare("SELECT left_node,right_node, right_node - left_node + 1 as width FROM product_categories WHERE name ='$node_name'");$stmt-execute();
$rs=$stmt-fetch(PDO::FETCH_ASSOC);
$left_node=$rs['left_node'];
$right_node=$rs['right_node'];
$width=$rs['width'];
$pdo-exec("DELETE FROM product_categories WHERE left_node BETWEEN $left_node AND $right_node");$pdo-exec("UPDATE product_categories SET right_node = right_node - $width WHERE right_node $right_node");$pdo-exec("UPDATE product_categories SET left_node = left_node - $width WHERE left_node $right_node");}
deleteNode('數(shù)碼產(chǎn)品');
完成之后表結(jié)構(gòu)如下:
可以看到用多叉樹的方式構(gòu)建無限分類,查詢的時候是非常簡便的.但是在插入新的節(jié)點和刪除節(jié)點時就比較麻煩了.
給你個原理吧
先找第一層
然后在里面遞歸獲取下一層的
如果你知道遞歸怎么寫的應(yīng)該就明白了