如何对无统一分隔符、长度不一的地址字段城市名做GROUP BY分组
提取地址中城市名并分组的实现方案
你的示例数据如下:
| Address | order id |
|---|---|
| Toronto - 123 | 1 |
| Toronto 3333 | 2 |
| Ottawa - 222 | 3 |
| Missouri 4444 | 1 |
核心逻辑
现有数据里的城市名全部在地址字段最开头,由纯英文字母组成,和后缀内容(门牌号、街道编号等)的边界是第一个非英文字母字符(可能是多空格、短横杠、数字),不需要统一分隔符,只要提取字段开头的连续英文字符段就能拿到准确城市名。
具体实现
根据你用的数据库类型选对应写法即可:
- 支持正则提取的数据库(MySQL 8.0+、PostgreSQL、Hive、Spark SQL、ClickHouse等)
用正则^[a-zA-Z]+匹配开头连续字母,直接分组即可,代码示例:
SELECT REGEXP_SUBSTR(`Address`, '^[a-zA-Z]+') AS city, COUNT(DISTINCT `order id`) AS order_total FROM your_table_name GROUP BY REGEXP_SUBSTR(`Address`, '^[a-zA-Z]+');
针对示例数据的运行结果:
| city | order_total |
|---|---|
| Toronto | 2 |
| Ottawa | 1 |
| Missouri | 1 |
- 不支持正则的低版本MySQL(5.x及更早版本)
先定位第一个数字出现的位置,截断前面的内容后清理掉多余的空格、短横杠即可:
SELECT TRIM(REPLACE(LEFT(`Address`, first_num_pos -1), '-', '')) AS city, COUNT(DISTINCT `order id`) AS order_total FROM ( SELECT *, LEAST( IFNULL(NULLIF(LOCATE('0', `Address`),0),999), IFNULL(NULLIF(LOCATE('1', `Address`),0),999), IFNULL(NULLIF(LOCATE('2', `Address`),0),999), IFNULL(NULLIF(LOCATE('3', `Address`),0),999), IFNULL(NULLIF(LOCATE('4', `Address`),0),999), IFNULL(NULLIF(LOCATE('5', `Address`),0),999), IFNULL(NULLIF(LOCATE('6', `Address`),0),999), IFNULL(NULLIF(LOCATE('7', `Address`),0),999), IFNULL(NULLIF(LOCATE('8', `Address`),0),999), IFNULL(NULLIF(LOCATE('9', `Address`),0),999) ) AS first_num_pos FROM your_table_name ) t GROUP BY city;
适配调整
如果后续数据出现带空格的城市名(比如New York、Los Angeles),只要把正则规则改成^[a-zA-Z\\s]+,匹配到第一个数字/短横杠前的内容即可,核心逻辑不变。正式分组前建议先执行SELECT DISTINCT 提取出的城市名 FROM 表做校验,确认无异常值再做统计。
内容的提问来源于stack exchange,提问作者Ali Naveed
相关产品推荐
相关产品推荐

