题目描述

contacts表中存储用户联系信息,需查询符合以下条件的电话号码,按id升序输出所有字段:

  • 电话号码的数字部分共10位,且第一位不能以0开头
  • 格式支持两种:
    • 连续10位数字(如1234567890);
    • 固定分隔格式(3-3-4结构,如123-456-7890)。

题目分析

本题核心是电话号码的格式校验,需同时满足数字长度、首位规则、格式规则三个条件:

  1. 数字长度:无论是否分隔,数字部分必须为10位。
  2. 首位规则:10位数字的第一位不能为0
  3. 格式规则:需精准匹配“连续10位”或“3-3-4 分隔”两种模式。

难点在于高效区分格式,并确保字符符合规则。

解法一:字符串函数组合(LEFT+LENGTH+LIKE)

这种方法适合不会用正则表达式的小伙伴~

select *
from contacts
where left(phone_number, 1) in ("1", "2", "3", "4", "5", "6", "7", "8", "9")
  and (length(phone_number) = 10 
       or phone_number like "___-___-____")
order by id asc;

代码关键点

  1. 首位校验: 通过LEFT(phone_number, 1)提取首位字符,判断其是否为1-9(排除0开头的非法情况)。
  2. 长度与格式校验
    • length(phone_number) = 10:匹配连续10位数字。
    • phone_number like "___-___-____":匹配 3-3-4 分隔格式(两个减号固定位置,使用占位符_分别表示前3位、中间3位、后4位)。

这个解法的缺点是没有办法完全排除电话号码中间有字母的情况,但可以解决本题的测试用例。

解放二(进阶版):正则表达式(REGEXP)

select *
from contacts
where phone_number regexp "^[1-9]([0-9]{9}|[0-9]{2}-[0-9]{3}-[0-9]{4})$"
order by id asc;

代码关键点

  1. 正则语法解析: 正则通过分支匹配| 表示 “或”)覆盖两种格式:
    • 分支1(连续数字格式):^[1-9][0-9]{9}$
      • ^ 标记字符串开头,$标记字符串结尾;
      • [1-9] 匹配首位(非0),[0-9]{9} 匹配后续9位数字。
    • 分支 2(分隔格式):^[1-9][0-9]{2}-[0-9]{3}-[0-9]{4}$
      • 前3位:[0-9]{2} 匹配前2位(结合首位共3位);
      • 中间3位:[0-9]{3} 匹配中间3位;
      • 后4位:[0-9]{4} 匹配最后4位。
  2. 正则表达总结
    • ^标记字符串开头,$标记字符串结尾;
    • [1-9]表示范围,{}为数量符,表示有几位;
    • | 表示“或”,可用()圈起来,逻辑更严谨。
  3. 优势与局限
    • 正则表达式更严谨,但语法较复杂;字符串函数更直观,适合简单场景。