Featured image of post PHP与MariaDB数据库实现的省市区三级联动下拉选择器

PHP与MariaDB数据库实现的省市区三级联动下拉选择器

我的省市区三级联动下拉选择器的思路或者说一些相关的碎碎念。

在数据库课设中遇到了制作省市区三级联动下拉选择器的需求,因为是数据库课设,最开始就想到了用数据库的方法来实现,所以首先就把所有省市区三级地址信息在数据库中都以六位行政区划代码的形式来存储的。因为不是主要需求,把联动选择器放在了最后去做。

而我的行政区划代码与名字的对应是以这样的形式放在数据库中的:

code name
110000 北京市
110101 东城区
110102 西城区
110105 朝阳区

我们知道,行政区划代码具有这样的特点,即前两位可唯一确定省级行政区,前四位可唯一确定地级行政区(这里把“市辖区”“省辖县”等视作虚拟存在的地级行政区)。例如,130200为唐山市的行政区划代码,由13就知道其属于河北省;320321为丰县的行政区划代码,由32就知道其属于江苏省,再由03就进一步知道其属于徐州市。

code name
130000 河北省
130100 石家庄市
130200 唐山市
320000 江苏省
320100 南京市
320300 徐州市
320302 鼓楼区
320321 丰县

本着不加入冗余信息的原则,我没有加两列外键指示所属的省、市之类的,打算全部交给数据库以外的层面去判断,确实数据库轻巧了,给自己挖的坑也多了。

三级选择器中,省份的列表是不会发生变化的,而市区两级都需要动态更新,JavaScript不可避,而且还不能直接写,还得用PHP给echo出来。

我开始好蠢地用了一些循环写,网页给我卡了几十秒才加载出来。数一数,我好像用了数量级达到1012次的SELECT语句……甚至,我还在用剪枝的思路跳过十的几次方次查询……

总之就是被自己蠢哭了!发现不对劲了就开始全部推倒重构,最终还是只想出了先SELECT *全部存起来再给JavaScript调用的办法。至少秒加载而且功能能用了。

好消息!我写的很蠢的代码已在MIT许可证下公开了!真的有人会用吗

我写的这个选择器一些特殊操作的处理是这样的:虚拟地级行政区直接在地市选择器中出现供选择,不设县的地级行政区下只出现与上级同名的一个虚拟县级行政区。这些都是在数据库层面上操作的。

然后我有一个把读出来的行政区划代码转换成人看的区划名的函数它是这样写的,上面仓库里没放,这个是还没开始设计选择器时就写好了的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function code2name($code){
    $link = @(mysqli_connect(HOST, USER, PSWD, DBNM, 3316)) or die("数据库连接失败!");
    $prov = floor($code / 10000) * 10000;
    $res = mysqli_fetch_assoc(mysqli_query($link, "SELECT * FROM divcode WHERE code = $prov"))['name'];
    $pref = floor($code / 100) * 100;
    $prefr = mysqli_fetch_assoc(mysqli_query($link, "SELECT * FROM divcode WHERE code = $pref"))['name'];
    if($prefr != "市辖区" && $prefr != "市辖县" && $prefr != "省辖县" && $prefr != "区辖县" && $prefr != $res) $res .=  $prefr;
    $countyr = mysqli_fetch_assoc(mysqli_query($link, "SELECT * FROM divcode WHERE code = $code"))['name'];
    if($countyr != $prefr) $res .=  $countyr;
    return $res;
}

该函数避免了展示地名时出现不必要的文字。

1
2
3
4
echo code2name(440104); // 打印“广东省广州市越秀区”
echo code2name(110108); // 打印“北京市海淀区”而不是“北京市市辖区海淀区”
echo code2name(469005); // 打印“海南省文昌市”而不是“海南省省辖县文昌市”
echo code2name(442001); // 打印“广东省中山市”而不是“广东省中山市中山市”