PHP获取某个表与其他表的关联关系算法
如图 电影movie有多个附表,如果通过movie表来找出多个与之关联的表。
本算法规则:
- 外键写法必须是X_id;
- A与B 1对多关系,中间表表名必须是A_B,且A_B,必须包含A_id,B_id外键;
算法如下:
---------------------更新-----------------------------------------------
1 function findRelation($db=['dbname','user','pwd','host'],$current,$father='') 2 { 3 static $pdo; 4 if(empty($father)) 5 { 6 $pdo=new PDO("mysql:host=".(isset($db[3])?$db[3]:'localhost').";dbname={$db[0]}",$db[1],(isset($db[2])?$db[2]:'')); 7 $pdo->exec('set names utf8'); 8 } 9 10 //临时数组,保存下面运行得出的数据 11 $tp=[]; 12 13 //当前表的所有字段信息 14 $self=$pdo->query('show full columns from '.$current); 15 16 //当前表是否中间表 17 $is_middle=0; 18 19 //检查当前表是否有附表id字段 20 while($row = $self -> fetch()) 21 { 22 //如果有发现以xxx_id命名的外键 23 if(stripos($row['Field'],'_id')!==FALSE) 24 { 25 //获取附表名 26 $extName=str_ireplace('_id','',$row['Field']); 27 28 //如果当前的”附表“ 名是父表名,记录保存字段 29 if($extName==$father) 30 { 31 $tp['_field'][$row['Field']]=[$row['Type'],$row['Default'],$row['Comment'],'parent_index']; 32 33 continue; 34 } 35 else 36 { 37 //当前表包含有 当前表外键中的附表名(即main_extName 包含有 extName_id),则此表为中间表 38 if(strpos($current,$extName)!==FALSE) 39 $is_middle=1; 40 41 //记录字段信息 42 $tp['_field'][$row['Field']]=[$row['Type'],$row['Default'],$row['Comment'],'next_index']; 43 44 //继续往下寻找附表关系
$tp[$extName]=findRelation($db,$extName,$current); 45 46 47 } 48 } 49 else//没发现外键,记录当前字段 50 { 51 $tp['_field'][$row['Field']]=[$row['Type'],$row['Default'],$row['Comment'],$row['Key']]; 52 } 53 } 54 55 //记录当前表是否中间表 56 if($is_middle) 57 $tp['_type']='middle'; 58 else 59 $tp['_type']='content'; 60 61 //获取当前表注释 62 $cms=$pdo->query("show table status from {$db[0]} where name='{$current}'"); 63 $one=$cms->fetch(); 64 $tp['_comment']=$one['Comment']; 65 66 //扫描以【当前表】_为开头的附表 67 $exts=$pdo->query('show tables like "'.$current.'_%"'); 68 while($ext = $exts -> fetch()) 69 { 70 //往下寻找当前表与每个附表的关系 71 $tp[$ext[0]]=findRelation($db,$ext[0],$current); 72 } 73 74 return $tp;//返回已记录的关联关系和字段信息 75 } 76 77 echo '<pre>'; 78 print_r(['movie'=>findRelation(['movieshop','root'],'movie')]); 79 echo '</pre>';
上述算法得出的数据格式如下:
/* ([主表]=>)[ [_field]=>[ [字段名] => [ [0] => 字段类型 [1] => 默认值 [2] => 字段注释 [3] => 字段索引 ], ..... ] , [_type]=>middle/content(多对多中间表/1对多内容表,不是中间表可忽略) , [_comment]=>表注释 , [附表名]=>[ [_field]=>[ [字段名] => [ [0] => 字段类型 [1] => 默认值 [2] => 字段注释 [3] => 字段索引 ], ..... ], [_type]=>middle/content(多对多中间表/1对多内容表,不是中间表可忽略) , [_comment]=>表注释 , [附表名]=>[ ............. ] , ............... ] , .......... ] */
------------------------------------------------------------------------------旧版---------------------------------------------------------------------------------------
<?php /* 2016-11-03 GaZeon -------------寻找表关系方法--------------- 主表:main 附表格式:main_extName 可能存在的表:extName 判断主附的对应关系方法: 如果main 有 extName_id 则 main与main_extName 为1对1关系 如果main_extName 【有 且只有 main_id外键】或 【main_extName 有其他外键但不包含extName_id外键 】 则 main与main_extName 为1对多关系 如果main_extName 有 main_id外键,且有 extName_id 外键,则 main与 extName为多对多关系 ,main_extName为中间表 与main为1对多关系 1,获取【当前表】的所有字段,并循环字段查找_id结尾的外键 { 2,如果查找到【当前表】的外键,则判断【外键所在的表】是否【当前表】的【上一级表】: [如果是,则【外键所在的表】为中间表,【当前表】与【外键所在的表】为1对多关系,跳过本次进入下次循环]; [如果不是,则【当前表】与【外键所在的表】为1对多关系,查找这个【外键所在的表】], } 3,【当前表】外键查找完后,扫描以【当前表】_为开头的表: [如果有,则循环轮流进入1程序]; 4,没有,当前关联关系到达最终点,返回本次运行得出的关系信息。 ----------------------------------------------------- 如果一个表没有任何外键 如果这个表没有附表,则为最终表 如果这个表有附表,则查找其附表,继续寻找其表的关联关系 */ $pdo=new PDO('mysql:host=localhost;dbname=MovieShop','root',''); $pdo->exec('set names utf8'); $relation=[]; function findRelation($current,$father='') { global $pdo; global $relation; //临时数组,保存下面运行得出的数据 $tp=[]; //当前表的所有字段信息 $self=$pdo->query('show full columns from '.$current); //当前表是否中间表 $is_middle=0; //检查当前表是否有附表id字段 while($row = $self -> fetch()) { //如果有发现以xxx_id命名的外键 if(stripos($row['Field'],'_id')!==FALSE) { //获取附表名 $extName=str_ireplace('_id','',$row['Field']); //如果当前的”附表“ 名是父表名,记录保存字段 if($extName==$father) { $tp['_field'][$row['Field']]=[$row['Type'],$row['Default'],'parent_index']; continue; } else { //当前表包含有 当前表外键中的附表名(即main_extName 包含有 extName_id),则此表为中间表 if(strpos($current,$extName)!==FALSE) $is_middle=1; //记录字段信息 $tp['_field'][$row['Field']]=[$row['Type'],$row['Default'],'next_index']; //继续往下寻找附表关系 $tp[$extName]=findRelation($extName,$current); } } else//没发现外键,记录当前字段 { $tp['_field'][$row['Field']]=[$row['Type'],$row['Default'],$row['Key']]; } } //记录当前表是否中间表 if($is_middle) $tp['_type']='middle'; else $tp['_type']='content'; //扫描以【当前表】_为开头的附表 $exts=$pdo->query('show tables like "'.$current.'_%"'); while($ext = $exts -> fetch()) { //往下寻找当前表与每个附表的关系 $relation[$current][$ext[0]]=findRelation($ext[0],$current); } return $tp;//返回已记录的关联关系和字段信息 } findRelation('movie'); echo '<pre>'; print_r($relation); echo '</pre>';
有bug请联系本人,转载需注明出处。