简介:这份资源是面向后端开发、数据分析与地理信息系统开发者的MySQL行政区划数据脚本,用于快速构建中国省份、城市及区县的层级化数据表,解决应用中地域信息存储与关联查询的基础需求。压缩包内共1个SQL文件,整体约69KB,文件为建表与数据填充脚本,可直接导入MySQL执行,省去手工整理行政区划数据的繁琐过程。资源围绕t_area.sql展开,表结构通常包含主键id、省份、城市、区县、行政区域编码、层级标识及父级ID等字段,通过parent_id串联省市区层级,便于使用JOIN或递归查询获取完整行政链,也可与人口、公司地址等业务表联合使用。目前已有638人学习下载,适合需要快速落地地域选择、物流地址、统计报表等场景的开发者参考使用。
1. 一份 t_area.sql 能省掉多少事:从省市区三级联动说起
做过电商收货地址、物流分单、门店区域归属的人都知道,省市区数据这东西,第一次接的时候觉得简单,真动手才发现是个体力活。要么去某个开放平台调接口,要么自己对着行政区划表一条条录,前者受网络和配额限制,后者纯属折磨。我手上这份「全国省份城市数据库表(mysql).zip」就是干这个的——解压出来一个t_area.sql,导入 MySQL 之后直接得到一张带层级关系的行政区划表,省、市、区县三级用parent_id串起来,还带国标行政编码。它适合谁?适合正在做地址选择器、运费模板、区域报表,又不想在基础数据上耗时间的后端和全栈。下面我按「先看懂表结构,再导入,再查询,最后避坑」的顺序拆一遍,你照着敲就能跑起来。
2. 先看懂 t_area.sql 的表结构:字段、层级与编码怎么设计
2.1 一张自关联表撑起三级行政区划
这类脚本的典型设计是一张自关联(self-referencing)表,而不是省、市、区三张独立表。为什么?因为三张表意味着三次 JOIN 才能拿到「省-市-区」完整链路,而自关联表用parent_id指向上级,一次递归或者几次自连接就能拼出层级。常见字段大致是这样:
| 字段 | 类型 | 含义 | 说明 |
|---|---|---|---|
| id | int / bigint | 主键 | 自增,程序内部关联用 |
| parent_id | int | 父级 ID | 顶级省份为 0 或 NULL |
| name | varchar | 名称 | 省 / 市 / 区县名 |
| code | char(6) / varchar | 行政编码 | 国标 6 位,如 110000 |
| level | tinyint | 层级 | 1 省、2 市、3 区县 |
| pinyin / initial | varchar | 拼音 / 首字母 | 部分脚本带,用于索引排序 |
拿到脚本先别急着导入,用编辑器打开扫一眼CREATE TABLE段,确认三件事:主键是不是自增、parent_id默认值是什么、code字段长度够不够。我见过有的脚本code只给了char(4),导入到一半报截断,血泪经验就是先看 DDL 再执行。
2.2 层级关系靠 parent_id,不靠名称拼接
新手容易犯的错是拿名称去拼层级,比如「广东省广州市」,靠字符串前缀匹配。这在实际业务里非常脆——重名、简称、别名一多就翻车。正确姿势是全程用id和parent_id走。举个查询:想拿某个市下面所有区县,只要WHERE parent_id = 该市id;想反查某个区县属于哪个省,就顺着parent_id往上找两级。这种结构对索引友好,也方便做缓存。
提示:导入前先确认脚本用的是
utf8mb4还是utf8。行政区划里有生僻字,utf8三字节在某些排序规则下会出问题,建议统一utf8mb4。
2.3 行政编码 code 的用途和坑
code是国标 6 位行政区划代码,前两位是省,中间两位是市,后两位是区县。它的价值在于跨系统对齐——对接第三方物流、税务、统计接口时,对方认的往往是 code 而不是你自增的 id。但要注意:行政区划会调整,某个区可能被撤销或合并,code 随之变化。所以如果你的业务对 code 敏感,别把它当永久主键,用自增 id 做内部关联,code 只做外部映射。
3. 导入 MySQL 的完整流程:命令行、客户端与字符集设置
3.1 建库建表再导入,别直接 source
最稳的流程是先建一个独立库,再导入脚本,避免污染现有库。命令行操作如下:
# 1. 登录 MySQL mysql -u root -p # 2. 建一个专用库,字符集跟脚本保持一致 CREATE DATABASE area_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 3. 切库 USE area_db; # 4. 导入脚本(在 MySQL 交互界面里执行,注意路径用绝对路径) source /your/path/t_area.sql;如果你不想进交互界面,也可以直接在系统 shell 里一条命令搞定:
mysql -u root -p area_db < /your/path/t_area.sql逻辑说明:source是在 MySQL 客户端内部执行文件,适合已经登录的场景;重定向<是 shell 层面把文件喂给客户端,适合脚本化。参数上,-u是用户名,-p后面不要跟密码(会明文留在历史里),回车后再输入。导入完成后用SHOW TABLES;确认表建出来了。
3.2 用客户端工具导入时的字符集陷阱
Navicat、DBeaver 这类图形工具导入 SQL 文件很方便,但字符集设置不对就会出乱码。以常见客户端为例,导入前要做两件事:一是把连接字符集设成utf8mb4,二是确认脚本文件本身的编码是 UTF-8 无 BOM。如果导入后发现省份名变成问号,八成是连接字符集用了latin1。补救办法是重新导入,别想着事后UPDATE修,成本更高。
-- 导入后立刻验证字符集和条数 SELECT COUNT(*) FROM t_area; SELECT * FROM t_area WHERE level = 1 LIMIT 5;COUNT(*)用来确认数据量是否符合预期(省级通常 30 多条,含港澳台),level = 1过滤出省份看名称是否正常显示。这两步花不了十秒,但能帮你早发现字符集问题。
3.3 导入失败时的排查顺序
导入报错别慌,按这个顺序查:第一,看报错行号,多半是某条INSERT的字段数对不上;第二,确认目标库字符集;第三,检查脚本里有没有DROP TABLE IF EXISTS,有的话说明它会覆盖同名表,别在正式库上直接跑。常见报错ERROR 1366 (HY000): Incorrect string value基本就是字符集问题,ERROR 1064是语法问题,通常是脚本被编辑器改过编码。
4. 查询与索引优化:三级联动、递归查询和常用 SQL
4.1 三级联动查询怎么写才不慢
前端省市区三级联动,本质是三次按parent_id查询。最朴素的做法是每次用户选择都查一次库:
-- 查所有省份 SELECT id, name FROM t_area WHERE parent_id = 0 AND level = 1; -- 根据省 id 查市 SELECT id, name FROM t_area WHERE parent_id = ? AND level = 2; -- 根据市 id 查区县 SELECT id, name FROM t_area WHERE parent_id = ? AND level = 3;逻辑说明:parent_id = 0是顶级省份的约定(有的脚本用 NULL,导入后先SELECT DISTINCT parent_id FROM t_area ORDER BY parent_id LIMIT 5;确认一下)。level条件是可选的冗余校验,加上更保险。参数?是占位符,实际用预处理语句传值,别拼字符串。
4.2 给 parent_id 和 code 建索引
上面三条查询如果没索引,数据量上万后每次联动都全表扫,体验会很差。建索引很简单:
-- parent_id 是联动查询的核心过滤字段 CREATE INDEX idx_parent ON t_area (parent_id); -- code 用于外部系统对齐,也常被查 CREATE INDEX idx_code ON t_area (code); -- 如果经常按名称搜索,可以加前缀索引 CREATE INDEX idx_name ON t_area (name(10));参数说明:idx_parent让WHERE parent_id = ?走索引;idx_code服务外部对接;name(10)是前缀索引,只取前 10 个字符建索引,省空间,适合模糊搜索场景。注意别给level单独建索引,区分度太低,优化器多半不用。
4.3 用自连接拼出「省-市-区」完整链路
有时候报表需要一行显示完整地址,用两次自连接就能拼出来:
SELECT p.name AS province, c.name AS city, d.name AS district FROM t_area d JOIN t_area c ON d.parent_id = c.id JOIN t_area p ON c.parent_id = p.id WHERE d.level = 3 LIMIT 10;逻辑说明:以区县d为起点,往上 JOIN 出市c,再往上 JOIN 出省p。这种写法在数据量不大时够用,但如果要查某个省下所有区县,自连接会比递归更直观。MySQL 8.0 以上还支持 CTE 递归,写法更优雅,但兼容性要考虑——如果你的环境还是 5.7,就老老实实用自连接。
5. 避坑与常见问题:导入、编码、层级那些翻车现场
5.1 导入后中文全是问号
现象:SELECT出来省份名显示???或乱码。原因:连接字符集或库字符集不是utf8mb4,脚本里的中文按错误编码写入。解决:删库重建,建库时显式指定DEFAULT CHARACTER SET utf8mb4,导入命令加--default-character-set=utf8mb4,图形工具里把连接编码也改成utf8mb4,然后重新导入。别试图用CONVERT修,数据已经错了,修不回来。
5.2 parent_id 顶级值到底是 0 还是 NULL
现象:查省份查不出来,WHERE parent_id = 0返回空。原因:不同脚本对顶级节点的约定不一样,有的用 0,有的用 NULL。解决:导入后先跑SELECT id, name, parent_id FROM t_area WHERE level = 1 LIMIT 3;看一眼实际值,再决定查询条件。如果混用,可以在应用层统一成 0,或者查询时写WHERE parent_id = 0 OR parent_id IS NULL。
5.3 行政区划更新导致 code 对不上
现象:对接第三方接口时,某个区的 code 在对方系统里查不到。原因:行政区划调整(撤县设区、合并)后,本地脚本还是旧数据。解决:这类静态数据要定期更新,别指望一次导入用三年。做法是保留一份更新记录,新脚本导入前先备份旧表,用code做比对,找出新增和失效的记录。如果业务对时效要求高,考虑把 code 映射做成配置,而不是硬编码在代码里。
5.4 递归查询把数据库拖垮
现象:用递归 CTE 查层级时,查询越来越慢甚至超时。原因:递归没有终止条件写对,或者数据里存在环(某条记录的 parent_id 指向了自己的后代)。解决:递归查询务必加WHERE限制层级深度,比如WHERE level < 4;导入后跑一次环检测,确认没有parent_id指向自身或形成闭环的脏数据。静态行政区划一般不会有环,但脚本被改过就说不准了。
6. 进阶用法:把 t_area 接进业务系统的几个实战技巧
数据导进来只是第一步,真正省事的是把它用顺。我一般会做三件事。第一件是加一层缓存:省市区数据几乎不变,没必要每次联动都查库,用 Redis 把parent_id -> 子节点列表缓存起来,key 设计成area:children:{parentId},更新数据时整体刷新。第二件是导出成前端能直接吃的 JSON,减少一次接口往返:
# 把 t_area 导出成嵌套 JSON,供前端本地联动 import json import pymysql conn = pymysql.connect(host='localhost', user='root', password='***', database='area_db', charset='utf8mb4') cur = conn.cursor(pymysql.cursors.DictCursor) cur.execute("SELECT id, parent_id, name, code, level FROM t_area ORDER BY id") rows = cur.fetchall() # 先按 parent_id 分组,再递归组装 children = {} for r in rows: children.setdefault(r['parent_id'], []).append(r) def build(pid): return [{'id': n['id'], 'name': n['name'], 'code': n['code'], 'children': build(n['id'])} for n in children.get(pid, [])] with open('area.json', 'w', encoding='utf-8') as f: json.dump(build(0), f, ensure_ascii=False) cur.close() conn.close()逻辑说明:children字典按parent_id把记录分组,build递归组装成树。参数上,charset='utf8mb4'必须写,否则中文乱码;ensure_ascii=False保证 JSON 里中文正常显示。这个脚本跑一次生成静态文件,前端直接加载,联动零延迟。注意build(0)的起点要和你的顶级parent_id约定一致,用 NULL 的话改成build(None)。
第三件是给地址表做外键约束。业务表里存province_id、city_id、district_id,查询时 JOINt_area拿名称。但别加数据库层面的外键,行政区划更新时外键会挡住你的批量操作,用应用层校验就够了。还有个细节:如果业务允许用户填海外地址,t_area里没有对应记录,字段要允许为空,别设NOT NULL。
最后说个验证方法。导入完成后,随机抽几个知名城市,用 code 反查名称,再顺着parent_id往上核对省份,跑通就说明层级和编码都对。从那以后我每次拿到这类静态数据脚本,都强制先跑一遍「抽三条三级链路核对」再往业务里接,省得后面返工。希望帮到你。
本文还有配套的精品资源,点击获取