简介:这是一份面向数据分析人员、Excel 使用者及 .NET 开发者的省市区三级联动数据资源,核心解决中国行政区划数据在表格与程序中按省、市、区逐级筛选联动的需求,可用于数据管理、统计分析和下拉选择框开发。压缩包共 21 个文件,约 2.1MB,以 9 个 dll 类库、6 个 pdb 调试文件、2 个 exe 程序、2 个 xml 配置及 1 个 xls 表格为主,其中 NPOI 负责读写 Excel,Ionic.Zip.Reduced 处理压缩,其余组件支撑数据获取与测试运行。资源内含完整的全国省市区数据源与演示程序,读者可直接查看三级联动效果,也能借助类库在自有项目中填充数据、设置样式并验证层级关系。目前已有 3934 人学习下载,适合需要快速获取行政区划数据或搭建联动功能的开发者参考使用。
1. 省市区三级联动 Excel 表格:一份能直接塞进后台的行政编码底表
做过后台系统的人多半遇到过这种场景:前端要一个省市区三级联动下拉框,产品经理说“很简单,网上找一个现成的数据就行”,结果你搜出来的要么是缺街道的、要么是编码对不上的、要么是某个省下面少了好几个地级市。更麻烦的是,有些表格看着全,实际用的时候发现字段名是中文、层级靠缩进、合并单元格满天飞,根本没法直接导入数据库。这份“最全省市区三级联动 Excel 表格”解决的就是这个前置问题——它把省、市、区县三级行政区域整理成结构化表格,字段清晰、层级明确,适合直接作为后台系统的地址库底表,也适合做数据清洗、地址解析、物流分单等场景。如果你正在搭管理后台、做用户地址模块,或者需要一份能直接跑 SQL 的行政区划数据,这份表格能省掉你至少半天到一天的整理时间。它不涉及任何复杂算法,价值全在“数据规整”这四个字上,但恰恰是这种基础数据,翻车率最高。
2. 拆开这份表格:字段设计、层级逻辑与选型理由
拿到一份 Excel 表格,第一件事不是急着导入,而是先看清楚它的字段结构和层级表达方式。很多人在这一步偷懒,后面就会遇到“省市区串位”“编码重复”“层级断裂”这类玄学问题。这份表格的设计思路是典型的扁平化存储,每一行代表一个最小行政单位(通常是区县),同时冗余存储它的上级省市信息,这样查询时不需要递归,直接 WHERE 就能出结果。
2.1 字段清单与含义
常见做法是至少包含以下字段,我一般会按这个顺序排列:
| 字段名 | 类型 | 说明 |
|---|---|---|
| province_code | 字符串 | 省级行政区划代码,通常 6 位 |
| province_name | 字符串 | 省/直辖市/自治区名称 |
| city_code | 字符串 | 市级行政区划代码,通常 6 位 |
| city_name | 字符串 | 地级市/自治州/盟名称 |
| district_code | 字符串 | 区县代码,通常 6 位 |
| district_name | 字符串 | 市辖区/县/县级市名称 |
| level | 整数 | 层级标识,1 省 2 市 3 区县 |
有些版本还会加parent_code或full_name,前者用于构建树形结构,后者用于直接展示“省市区”拼接后的全称。如果你的系统需要做级联查询,parent_code很有用;如果只是做下拉框,full_name能省掉前端拼接。选型时先确认你的业务需不需要街道/乡镇级,这份表格通常到区县为止,街道级需要另外补充。
2.2 层级表达与编码规则
行政区划代码不是随便编的,它遵循 GB/T 2260 标准,前两位是省级,中间两位是市级,后两位是区县级。比如110101代表北京市东城区,110000是北京市,110100是市辖区。这份表格的编码字段如果严格按照这个规则,你就能用字符串截取快速做层级判断:
# 根据区县代码反推省市代码 district_code = "110101" province_code = district_code[:2] + "0000" # 110000 city_code = district_code[:4] + "00" # 110100逻辑说明:前两位加四个零得到省级代码,前四位加两个零得到市级代码。参数上要注意,直辖市和特殊行政区(如省直辖县级行政区)的市级代码可能不是标准截取结果,需要以表格实际数据为准。我一般会先用LEN和LEFT在 Excel 里做一次校验,确认没有异常长度再入库。
2.3 为什么不用 JSON 或 CSV 而用 Excel
Excel 的优势在于肉眼可查、方便非技术人员核对。你让运营同事确认“这个市下面是不是少了某个区”,给他 Excel 比给他 JSON 文件靠谱得多。而且 Excel 可以直接做筛选、排序、去重,导入数据库前能快速做一轮人工校验。CSV 虽然轻量,但编码问题(UTF-8 BOM、GBK)经常导致中文乱码,Excel 在保存时可以明确选择编码格式,反而少一层坑。当然,最终入库时还是建议转成 CSV 或直接走数据库导入工具,Excel 只作为中间校对层。
3. 从 Excel 到数据库:导入流程与字段映射实战
表格看懂了,下一步就是把它变成系统能用的数据。这一步的核心是“字段映射”和“数据清洗”,顺序不能反。先清洗再映射,否则脏数据会污染目标表结构。我一般会走四步:Excel 预处理、导出 CSV、建目标表、批量导入并校验。
3.1 Excel 预处理:去合并单元格与补全空值
合并单元格是导入的头号杀手。如果省市字段是合并的,导入后只有第一行有值,后面全是空。处理方法是选中整列,取消合并,然后定位空值批量填充。具体操作:选中 A 列,取消合并单元格,按Ctrl+G定位条件选“空值”,输入=A2后按Ctrl+Enter批量填充。市级字段同理。这一步做完,每一行都应该是完整的省市区三级信息。
提示:操作前先复制一份原始表格,避免改坏后无法恢复。
3.2 导出 CSV 与编码选择
Excel 另存为 CSV 时,默认可能是 GBK 编码,而数据库和程序通常用 UTF-8。建议在“另存为”对话框里选择“CSV UTF-8(逗号分隔)”,或者用 Python 的 pandas 直接读取 Excel 再写出 CSV:
import pandas as pd # 读取 Excel,指定 sheet 名 df = pd.read_excel("行政区划表.xlsx", sheet_name="省市区", dtype=str) # 去除首尾空格,避免“北京市 ”这种带空格的脏数据 df = df.apply(lambda col: col.str.strip() if col.dtype == "object" else col) # 写出 UTF-8 无 BOM 的 CSV,方便后续导入 df.to_csv("region.csv", index=False, encoding="utf-8")逻辑说明:dtype=str强制所有列按字符串读取,防止区县代码被当成数字丢掉前导零。str.strip()处理肉眼看不见的空格。encoding="utf-8"不带 BOM,避免某些数据库导入时第一列字段名带隐藏字符。参数上,如果你的 Excel 有多个 sheet,sheet_name要写对;如果表格有表头行不在第一行,用skiprows跳过。
3.3 建表 SQL 与导入命令
目标表结构要和 CSV 字段一一对应,建议加一个自增主键和索引:
CREATE TABLE region ( id INT AUTO_INCREMENT PRIMARY KEY, province_code VARCHAR(6) NOT NULL, province_name VARCHAR(50) NOT NULL, city_code VARCHAR(6) NOT NULL, city_name VARCHAR(50) NOT NULL, district_code VARCHAR(6) NOT NULL, district_name VARCHAR(50) NOT NULL, level TINYINT NOT NULL DEFAULT 3, INDEX idx_province (province_code), INDEX idx_city (city_code), INDEX idx_district (district_code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;导入用LOAD DATA最快:
LOAD DATA LOCAL INFILE 'region.csv' INTO TABLE region FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 ROWS (province_code, province_name, city_code, city_name, district_code, district_name, level);逻辑说明:IGNORE 1 ROWS跳过 CSV 表头。ENCLOSED BY '"'处理字段里可能出现的逗号。如果导入后中文乱码,检查数据库连接字符集和 CSV 编码是否一致。参数上,level字段如果 CSV 里没有,可以在导入时用SET level=3固定赋值。
3.4 导入后校验:三查三对
导入完成不代表结束,我一般会跑三条校验 SQL:
-- 查总数,和 Excel 行数对比 SELECT COUNT(*) FROM region; -- 查省级去重数量,正常应该是 34 左右(含港澳台) SELECT COUNT(DISTINCT province_code) FROM region; -- 查有没有区县代码重复 SELECT district_code, COUNT(*) FROM region GROUP BY district_code HAVING COUNT(*) > 1;如果省级数量明显偏少,说明有省份在清洗时被合并或丢失;如果区县代码重复,说明数据源本身有重复行,需要去重。这三步做完,基本能确认数据完整可用。
4. 避坑与排查:三级联动数据最常见的五个翻车点
这份表格本身质量不错,但使用过程中还是有几个高频坑,我按“现象 → 原因 → 解决”整理出来,你遇到问题时可以直接对号入座。
4.1 导入后区县代码前导零消失
现象:110101变成110101看着正常,但010101这类代码变成10101,位数不对。原因:Excel 或数据库把代码字段当成了数字类型。解决:Excel 里先把该列格式设为“文本”,数据库建表时用VARCHAR而不是INT,导入时 pandas 指定dtype=str。
4.2 直辖市层级错乱
现象:北京市下面的“市辖区”被当成一个市级单位,导致前端下拉框出现“北京市 → 市辖区 → 东城区”这种奇怪层级。原因:直辖市的行政编码里,市级代码110100对应的名称是“市辖区”,不是真正的城市名。解决:在数据清洗时把直辖市和特殊行政区的市级名称统一替换为省级名称,或者在前端做特殊判断,跳过市级直接展示区县。
4.3 省直辖县级行政区没有市级归属
现象:某些省下面的县级市(如省直辖)在表格里city_code为空或等于省级代码。原因:行政区划调整后,这些县级单位由省直接管辖,没有地级市代管。解决:在数据库里给这类记录补一个虚拟市级,或者在前端级联逻辑里允许市级为空时直接展示区县。
4.4 同名区县导致查询串数据
现象:搜索“城关区”出来好几个不同省份的结果,前端只显示名称时用户无法区分。原因:全国同名区县很多,仅靠名称查询会命中多条。解决:查询时强制带上province_code或city_code作为条件,展示时用full_name拼接全称。
4.5 Excel 行数虚高或虚低
现象:Excel 显示几万行,导入后只有几千条。原因:表格末尾有大量空行,或者中间有隐藏行被误删。解决:导入前用df.dropna(how="all")去掉全空行,用df.drop_duplicates()去重,再和原始行数对比确认。
5. 进阶用法:用 Python 做地址解析与级联查询接口
数据入库后,真正的价值在于怎么用。除了前端下拉框,这份表格还能支撑地址解析、物流分单、用户地域统计等场景。我一般会封装两个函数:一个做地址字符串解析,一个做级联查询。
5.1 从一段地址文本反查三级编码
用户填的地址是“广东省深圳市南山区科技园”,你需要拆出省市区并匹配编码。思路是用省市区的名称去数据库做前缀匹配,优先匹配最长的名称。
import pymysql def parse_address(address): conn = pymysql.connect(host="localhost", user="root", password="", db="test", charset="utf8mb4") cursor = conn.cursor() # 先查省级 cursor.execute("SELECT province_code, province_name FROM region WHERE %s LIKE CONCAT(province_name, '%%') LIMIT 1", (address,)) province = cursor.fetchone() if not province: return None # 再查市级,限定在已匹配的省内 cursor.execute("SELECT city_code, city_name FROM region WHERE province_code=%s AND %s LIKE CONCAT(city_name, '%%') LIMIT 1", (province[0], address)) city = cursor.fetchone() # 最后查区县 cursor.execute("SELECT district_code, district_name FROM region WHERE city_code=%s AND %s LIKE CONCAT(district_name, '%%') LIMIT 1", (city[0] if city else province[0], address)) district = cursor.fetchone() conn.close() return { "province": province, "city": city, "district": district }逻辑说明:LIKE CONCAT(province_name, '%')用地址文本去匹配名称开头,LIMIT 1防止同名干扰。参数上,如果地址里省市区顺序不标准,需要先做分词或正则提取,这个函数只适合标准顺序的地址。实际项目中我还会加一层缓存,避免每次查询都打数据库。
5.2 级联查询接口的 SQL 写法
前端下拉框的典型请求是:先查所有省,再根据省查市,再根据市查区。对应 SQL 很简单:
-- 查所有省 SELECT DISTINCT province_code, province_name FROM region ORDER BY province_code; -- 根据省代码查市 SELECT DISTINCT city_code, city_name FROM region WHERE province_code = '440000' ORDER BY city_code; -- 根据市代码查区县 SELECT district_code, district_name FROM region WHERE city_code = '440300' ORDER BY district_code;注意DISTINCT不能省,因为扁平化存储下同一个省会出现很多行。如果数据量大,建议在province_code和city_code上建索引,查询速度会明显提升。
5.3 一个我踩过的坑:编码更新滞后
行政区划代码不是一成不变的,每年都可能有个别区县撤并或更名。我早期做项目时直接拿了一份三年前的表格,结果上线后用户反馈“某某区”选不到,一查才发现该区已经合并到另一个区了。从那以后我每次用这类表格,都会先确认数据版本,并在数据库里加一个updated_at字段记录导入时间。如果你的系统对地址准确性要求高,建议每半年核对一次官方发布的行政区划代码,或者至少留一个手动修正的入口。希望帮到你。
本文还有配套的精品资源,点击获取