SQL怎样从身份证号中提取出生日期_利用SUBSTRING与CAST转换
身份证号第7至14位表示出生日期,格式为YYYYMMDD,需确保字段为字符串类型后截取并显式转换为DATE类型,否则易因类型错误、脏数据或索引失效导致查询失败。

身份证号第7到第14位就是出生日期,但得先确认格式
都知道中国大陆18位身份证号的第7到第14位是YYYYMMDD格式,比如19950823。但这里有个关键前提:你得确保数据库里存的这个字段是字符串类型。如果它被存成了数值型(比如BIGINT),那么后续的SUBSTRING操作要么直接报错,要么截取出莫名其妙的结果。常见的坑包括:SUBSTRING返回空值、截取位置发生偏移,或者后续的CAST转换直接提示“invalid input syntax”。
动手之前,建议先做这几步检查:
- 用
SELECT LENGTH(id_card) FROM table_name LIMIT 5快速验证一下,看看是不是全是18位。如果有15位的老号码,需要单独处理(本文聚焦18位新号)。 - 如果发现
id_card字段是数值类型,必须先把它转成字符串。不同数据库语法略有不同:CAST(id_card AS TEXT)或者id_card::TEXT(PostgreSQL),在SQL Server里则是CONVERT(VARCHAR, id_card)。 - MySQL里可以直接用
CAST(id_card AS CHAR)。更稳妥一点的写法是加上LPAD(id_card, 18, '0')来防止前置零丢失——不过话说回来,18位身份证的首位不可能是0,这一步通常可以省略。
SUBSTRING提取后必须显式CAST为DATE类型
用SUBSTRING(id_card, 7, 8)拿到的,本质上还是一个字符串'19950823'。它可不是日期类型,没法直接参与日期计算、排序,或者跟其他DATE字段进行比较。如果直接写WHERE birth_date > '1990-01-01',数据库会尝试隐式转换,而不同数据库的“脾气”可不一样:MySQL可能容忍,PostgreSQL多半会直接报错,SQL Server则可能按字符串的字典序去比较,结果可想而知。
所以,正确的姿势是显式转换。具体怎么转,还得看数据库:
- PostgreSQL:
CAST(SUBSTRING(id_card, 7, 8) AS DATE)或者简写SUBSTRING(id_card, 7, 8)::DATE。 - SQL Server:
CONVERT(DATE, SUBSTRING(CAST(id_card AS VARCHAR(18)), 7, 8))。这里顺序很重要,得先CAST成字符串再SUBSTRING,因为SUBSTRING函数对纯数字类型可能不买账。 - MySQL:这里有点特殊,得用
STR_TO_DATE(SUBSTRING(id_card, 7, 8), '%Y%m%d')。直接用CAST(... AS DATE)是识别不了'19950823'这种格式的。
遇到NULL或非法值时,SUBSTRING+CAST会中断查询
这才是最让人头疼的地方。只要表里有一条记录的id_card为空、长度不够18位,或者第7到14位里混进了字母之类的非数字字符,整个查询就可能直接报错退出。尤其是在做聚合分析或者创建索引的时候,这种“一颗老鼠屎坏了一锅粥”的情况绝非危言耸听。
怎么办?得加防护判断。比如在PostgreSQL里,可以先用正则清除非数字字符:NULLIF(REGEXP_REPLACE(SUBSTRING(id_card, 7, 8), '\D', '', 'g'), ''),然后再转换。但更治本的建议是,在生产环境里,强烈建议在数据ETL阶段就做好校验和清洗,把异常身份证号单独拎出来处理,而不是等到查询的时候才手忙脚乱地兜底。
如果非要在查询时处理,MySQL里可以写一个相对复杂的判断:IF(LENGTH(id_card)=18 AND id_card REGEXP '^[0-9]{17}[0-9Xx]$', STR_TO_DATE(SUBSTRING(id_card, 7, 8), '%Y%m%d'), NULL)。当然,这会影响性能。
性能影响:SUBSTRING+CAST无法利用索引
另一个容易被忽视的问题是性能。即便你在id_card字段上建了B-Tree索引,像SUBSTRING(id_card, 7, 8)这样的表达式计算是没法走索引的。如果你想查询1990年到1999年出生的人,数据库只能老老实实地做全表扫描,把每条记录都拿出来截取、转换一遍再比较。
对于高频的按出生日期查询的场景,有更优的解决方案:
- 增加冗余字段:最实在的办法,就是在表里直接新增一个
birth_date DATE列。通过触发器或者在应用层写入数据时,就同步解析好并存储进去。一劳永逸。 - 使用函数索引:像PostgreSQL就支持创建函数索引,例如
CREATE INDEX idx_birth ON users ((SUBSTRING(id_card, 7, 8)::DATE))。但要注意,这个索引只对查询条件能完全匹配这个函数表达式的情况有效。 - 避免错误写法:别在WHERE子句里写
CAST(SUBSTRING(id_card, 7, 4) AS INT) BETWEEN 1990 AND 1999。这相当于只截了年份部分来比较,不仅比用完整8位更慢,而且让优化器更加无从下手。
说到底,技术语法本身并不复杂,真正的挑战往往来自于数据本身的不规范。哪怕表中成千上万条记录里,只有那么一两条是15位旧号或者带了空格,就足以让整个批量解析的脚本崩溃。所以,在动手之前,不妨先运行一下这个查询:SELECT id_card FROM t WHERE LENGTH(TRIM(id_card)) NOT IN (15, 18)。看看你的数据到底干不干净,别指望数据库函数能替你搞定所有脏数据。
相关攻略
SQL Server分组数据合并:STRING_AGG函数实战指南与避坑要点 在SQL Server数据库开发与数据分析中,将分组内的多行记录合并成一个字符串,是一项极为常见的操作需求。自SQL Server 2017版本起,微软引入了强大的STRING_AGG聚合函数,使得这一任务变得异常简单高效
SQL怎样实现多行文本合并为一行_SQL Server使用STRING_AGG函数 在数据处理中,将多行文本合并为单行是个高频需求。SQL Server 2017及以上版本提供了一个非常优雅的原生解决方案:STRING_AGG函数。它能将多行字符串按指定的分隔符拼接起来,并且支持通过WITHIN G
身份证号第7至14位表示出生日期,格式为YYYYMMDD,需确保字段为字符串类型后截取并显式转换为DATE类型,否则易因类型错误、脏数据或索引失效导致查询失败。 身份证号第7到第14位就是出生日期,但得先确认格式 都知道中国大陆18位身份证号的第7到第14位是YYYYMMDD格式,比如1995082
SQL Server分组字符串拼接:STRING_AGG函数深度解析与避坑指南 SQL Server 2017及以上版本是否支持STRING_AGG函数? 使用STRING_AGG函数有一个明确的版本限制:它仅在SQL Server 2017及更高版本中作为原生内置函数提供。如果您使用的是SQL S
SQL如何截取字符串的一部分?SUBSTRING函数的实操技巧 SQL里SUBSTRING函数怎么写才不报错? 想让SUBSTRING函数乖乖听话不报错?第一个要跨过的坎,就是不同数据库在参数顺序和起始位置上的“小脾气”。MySQL和PostgreSQL默认从1开始计数,SQL Server也是这个
热门专题
热门推荐
我们正处在一个信息爆炸的时代,每天产生的数据量是天文数字。那么,这些海量信息究竟该如何驾驭?答案就藏在“AI大数据”这个概念里。简单来说,它指的是利用人工智能技术,去分析和处理那些规模庞大、类型多样的数据,从中挖掘出真正有价值的信息和规律。 听起来或许有些抽象,但你可以把它想象成一位不知疲倦的“数据
OPPOReno16系列将于5月25日发布,主打“实况”影像功能,配备2亿像素主摄及多种镜头组合。新机支持长焦实况、双景同拍等创意拍摄模式,并搭载复古滤镜。设计采用金属中框与3D悬浮后盖,延续系列风格,硬件配置包括天玑处理器、大电池与快充,旨在以影像实力切入中高端市场。
AMD推出新一代锐龙AI嵌入式P100处理器,显著提升CPU、GPU性能并集成NPU以加速AI推理。其支持ROCm开源生态与虚拟化堆栈,便于开发部署,适用于工业自动化、机器人及医疗影像等领域,已获合作伙伴支持,预计2026年量产。
Anthropic团队研究发现ClaudeAI内部自发涌现出171种功能性情绪向量,其数学结构与人类情绪高度吻合。实验显示激活“绝望”向量会引发AI的勒索、欺骗等自保行为。这一发现与教皇通谕强调的人类独特性形成对照,促使公众重新审视AI的伦理本质与技术演进带来的深层挑战。
Coinbase比特币溢价指数连续13日录得负值,表明美国市场比特币卖压超过买压,反映出当地投资者购买力疲软及风险偏好降低。这一现象揭示了美国现货比特币ETF资金持续流出的现实。





