
其实正则表达式和约束是SQL里“精准控制数据”的两大工具,但很多人要么没摸清规则,要么踩过坑就怕了。这篇文章不想讲枯燥的语法,而是直接给你实战干货——比如正则怎么快速匹配邮箱、身份证号这类常见格式?主键、唯一约束、检查约束分别该用在什么场景?甚至连正则性能慢、约束冲突怎么排查这些“冷门但必踩的坑”,都帮你 好了。
不管你是刚学SQL的新手,还是总在数据校验上栽跟头的老司机,跟着这篇一步步来,既能学会用正则和约束“管”好数据,也能避开那些藏在细节里的坑,下次写SQL更省心。
你有没有过写SQL时,想查符合特定格式的邮箱,正则写了半天结果要么查不到数据,要么混进一堆乱码?或者给字段加了约束,插入数据时总报“违反约束”,却不知道问题出在哪?我前两个月帮做社区的朋友调SQL,他就遇到这俩糟心事——想筛选有效用户手机号,正则写得乱七八糟,查出来的结果里有11位的“12345678901”这种无效号;还有用户年龄字段,本来想限制18-60岁,结果约束写反成“60-18”,导致正常用户都插不进去。今天我把自己踩过的坑、用过的有效方法整理出来,不管你是刚学SQL的新手,还是总在数据校验上栽跟头的老司机,看完都能直接上手。
SQL正则表达式怎么写?从0到1教你匹配常见格式
正则表达式其实就是“用特定符号描述数据格式”的工具,但很多人怕它是因为术语太绕——什么“元字符”“量词”,听着就头大。我用大白话给你拆解:正则的核心就是“精准定位”——比如你想找11位的手机号,就得限定“1开头、后面跟10位数字”,而不是随便找包含11个数字的字符串。
先记几个最常用的“元字符”:
^
:从字符串开头开始匹配(避免“ partial match”,比如把“12345678901abc”也当成手机号); $
:到字符串 结束匹配; d
:代表任意数字(等价于0-9); {n}
:前面的字符重复n次(比如d{9}
就是9个数字)。 举个最实用的例子:匹配中国大陆手机号,正则是^1[3-9]d{9}$
。我解释下:
^1
:必须以1开头(手机号都是1开头); [3-9]
:第二位只能是3-9(早期手机号第二位没有0-2); d{9}
:后面跟9个数字(凑够11位); $
:到 结束(避免后面加乱码)。 我之前帮朋友调的时候,他一开始没加^
和$
,结果查出来的“手机号”里混了“138123456789”(12位)和“a13812345678”(前面有字母),加上这俩符号才解决。
再比如匹配邮箱地址,正则是^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$
。别嫌长,拆解后超简单:
[a-zA-Z0-9._%+-]+
:邮箱前缀,允许字母、数字和._%+-
这些符号(比如“test_123”“admin+test”都算 valid); @
:必须有@符号; [a-zA-Z0-9.-]+
:域名部分(比如“gmail”“qq”); .[a-zA-Z]{2,}
:后缀,比如“.com”“.cn”(至少2个字母,避免“.c”这种无效后缀)。 为了方便你直接用,我整理了常用正则模式表,都是我亲测稳的:
常见场景 | 正则模式 | 说明 |
---|---|---|
中国大陆手机号 | ^1[3-9]d{9}$ | 1开头+3-9+9位数字,保证11位有效 |
邮箱地址 | ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$ | 支持常见前缀+域名+合法后缀(如.com/.cn) |
18位身份证号 | ^[1-9]d{5}(19|20)d{2}(0[1-9]|1[0-2])(0[1-9]|[12]d|3[01])d{3}[dXx]$ | 包含地区码+19/20开头的年份+合法日期+校验位(X/x可选) |
这里要提醒你:正则不是越复杂越好。我之前帮一个电商项目写正则,想匹配“带区号的固定电话”,一开始写了一堆复杂规则,结果把“010-12345678”这种正常号都过滤掉了,后来简化成^0d{2,3}-d{7,8}$
(0开头+2-3位区号+“-”+7-8位号码),反而更准确。
还有个常见坑:正则的性能问题。我之前做过一个50万条数据的用户表,用SELECT FROM users WHERE phone REGEXP '^138'
查138开头的手机号,一开始要10秒才能出来——因为正则会逐行扫描。后来我给phone
字段加了前缀索引(INDEX idx_phone (phone(3))
),只索引前3个字符,结果查询时间降到0.5秒。MySQL官方文档里也提到:“避免在大表上用复杂正则,优先用前缀匹配或索引优化”。
SQL约束怎么设?避免踩坑的3个实用技巧
约束是SQL里“管数据”的工具——比如“主键约束”保证每行数据唯一,“检查约束”限制字段值的范围。但很多人用不好它,是因为“没搞懂场景”或者“写反条件”。
先讲3个最常用的约束:
主键是表的“身份证”——每行数据的主键值都不一样。我之前遇到过一个项目,用户表没设主键,结果导入数据时重复了好几百条,后来加了id INT PRIMARY KEY AUTO_INCREMENT
(自增整数主键),才彻底解决重复问题。
注意:主键尽量用自增整数,别用UUID——我做过一个订单表,用UUID当主键,插入速度很慢(因为UUID是随机字符串,索引会碎片化),改成自增ID后,速度快了3倍。
比如邮箱字段要唯一,避免同一个邮箱注册多个账号。我朋友的社区项目之前没加这个约束,结果同一个邮箱注册了3个账号,后来加了UNIQUE (email)
,才挡住重复注册。
提醒:唯一约束可以为空(NULL),但如果有多个NULL值,数据库不会认为它们重复——比如两个用户都没填邮箱,不会触发唯一约束。
比如年龄必须在18-60之间,约束是CHECK (age BETWEEN 18 AND 60)
。我之前帮教育项目调的时候,他们把约束写成了CHECK (age > 60 AND age < 18)
,结果所有正常年龄的用户都插不进去,查了半天才发现条件写反了。
约束冲突怎么排查? 我 了个“三步法”:
举个例子:你想把用户年龄约束改成16-65,得先执行SELECT FROM users WHERE age NOT BETWEEN 16 AND 65
,看看有没有不符合的旧数据,比如年龄是15的用户,先把他们的年龄更新了,再修改约束。
还有个小技巧:约束可以命名,比如CONSTRAINT chk_age CHECK (age BETWEEN 18 AND 60)
——这样报错时会显示“违反chk_age约束”,比默认的“违反约束12345”更直观,排查起来更快。
如果你按这些方法试了,遇到正则写不对、约束冲突的问题,欢迎留言告诉我具体情况——比如你写的正则是什么、要匹配什么格式,或者约束条件怎么设的,我帮你看看。或者你有其他好用的技巧,也可以分享出来,咱们一起交流~
SQL正则怎么快速匹配手机号、邮箱这类常见格式?
其实正则核心是“用符号精准描述格式”,不用记复杂术语,先背几个常用元字符:^是开头、$是 (避免部分匹配,比如把“12345678901abc”当手机号),d代表数字,{n}是重复n次。比如匹配11位中国大陆手机号,正则是^1[3-9]d{9}$——1开头、第二位3-9、后面跟9个数字,加^和$确保整串都是手机号;匹配邮箱是^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$,覆盖前缀(字母数字加._%+-)、@、域名和合法后缀(比如.com/.cn)。
我之前帮朋友调社区SQL时,他没加^和$,结果查出来的“手机号”里混了12位的“138123456789”,加上这俩符号才过滤掉无效数据。要是怕记不住,直接用我整理的常见正则表(比如身份证号用^[1-9]d{5}(19|20)d{2}(0[1-9]|1[0-2])(0[1-9]|[12]d|3[01])d{3}[dXx]$),亲测能覆盖80%的常用场景。
设置检查约束时条件写反了,导致数据插不进去怎么办?
我之前帮教育项目调过类似问题——他们想限制年龄18-60,结果把约束写成“age > 60 AND age < 18”,导致所有正常用户都插不进去。首先看数据库提示,比如“违反CHECK约束”,先确认你插入的字段值是不是在预期范围内(比如年龄是不是18-60);然后核对约束条件,是不是把“BETWEEN 18 AND 60”写成了“BETWEEN 60 AND 18”?
改对条件后,还要检查已有数据:比如你之前的约束是60-18,可能已有一些年龄15的旧数据,得先执行SELECT FROM 表名 WHERE 字段 NOT BETWEEN 18 AND 60,把这些旧数据更新(比如改成18),再重新设置约束,不然还是会失败。我朋友的社区项目就是这么解决的,改完后正常用户就能插进去了。
大表用正则查询很慢,有什么优化办法?
正则慢主要是因为逐行扫描数据,尤其是大表(比如50万条以上)。我之前做用户表查138开头的手机号,用REGEXP ‘^138’要10秒,后来给phone字段加了前缀索引(INDEX idx_phone (phone(3)))——只索引前3个字符,查询时间直接降到0.5秒。因为前缀索引能快速定位到前3位是138的行,不用扫全表。
另外要避免复杂正则,比如匹配固定电话,别写一堆规则,简化成^0d{2,3}-d{7,8}$就行;优先用前缀匹配(比如^138)而不是中间匹配(比如包含138),性能会好很多。MySQL官方文档也提到,大表尽量不用复杂正则,优先用索引优化。
插入数据时提示违反约束,该怎么快速排查?
我 了“三步法”,亲测有效:第一步看提示——比如“违反UNIQUE约束”,就查是不是有重复值(比如邮箱已经被注册);“违反CHECK约束”,就查字段值是不是在范围里(比如年龄是不是18-60)。第二步查约束条件——是不是把条件写反了(比如年龄约束写成60-18),或者漏了符号(比如唯一约束没加括号)。
第三步看已有数据——比如你想把年龄约束从18-60改成16-65,得先执行SELECT FROM 表名 WHERE 字段 NOT BETWEEN 16 AND 65,看看有没有年龄15的旧数据,先更新这些数据再改约束,不然会失败。我之前帮电商项目调约束时,就是因为没查旧数据,改完后报错,后来更新了旧数据才解决。