寻求高效简洁的SQL脚本实现:从Table1的statement列匹配地点列表生成location列
高效匹配地点生成新列的SQL优化方案
嘿,我明白你为啥不想写一堆CASE WHEN了——不仅代码冗长,以后要加新地点还得挨个修改条件,维护起来太费劲。这里有两个更简洁高效的方案,适配大多数主流数据库,还能让地点列表的维护灵活很多:
方案一:用正则表达式一次性匹配所有地点(适合支持正则的数据库)
如果你的数据库支持正则表达式提取,直接把地点列表拼成正则分支,就能一次性匹配出结果,不用写一堆条件。
比如在PostgreSQL中:
SELECT statement, (SELECT unnest(regexp_matches(statement, '(' || array_to_string(ARRAY['Tema', 'london', 'Sydney', 'Germany', 'China', 'Africa'], '|') || ')', 'gi'))) AS location FROM Table1;
这里把所有地点用|拼接成正则的“或”匹配模式,gi参数确保大小写不敏感匹配,regexp_matches会返回匹配到的地点数组,unnest把数组转成单行值。
如果是MySQL,可以用REGEXP_SUBSTR实现类似效果:
SELECT statement, REGEXP_SUBSTR(statement, 'Tema|london|Sydney|Germany|China|Africa', 1, 1, 'i') AS location FROM Table1;
'i'参数表示不区分大小写,函数会返回第一个匹配到的地点。
方案二:临时地点表JOIN(通用所有数据库,维护性拉满)
这种方法的核心是把地点列表做成一个临时表,然后通过模糊匹配JOIN原表,后续要加/改地点,只需要修改临时表的内容就行,完全不用动主查询逻辑。
用CTE(公共表表达式)实现的话:
WITH locations AS ( SELECT 'Tema' AS loc UNION ALL SELECT 'london' UNION ALL SELECT 'Sydney' UNION ALL SELECT 'Germany' UNION ALL SELECT 'China' UNION ALL SELECT 'Africa' ) SELECT t1.statement, l.loc AS location FROM Table1 t1 JOIN locations l ON t1.statement ILIKE '%' || l.loc || '%';
ILIKE是PostgreSQL里的不区分大小写模糊匹配,如果你用MySQL可以换成LIKE(配合数据库的大小写不敏感配置)或者LOWER(t1.statement) LIKE LOWER('%' || l.loc || '%');SQL Server可以用LIKE结合COLLATE来实现不区分大小写。
如果你的statement里可能同时包含多个地点,想只保留第一个匹配的结果,可以用窗口函数过滤:
WITH locations AS ( SELECT 'Tema' AS loc UNION ALL SELECT 'london' UNION ALL SELECT 'Sydney' UNION ALL SELECT 'Germany' UNION ALL SELECT 'China' UNION ALL SELECT 'Africa' ), matched_results AS ( SELECT t1.statement, l.loc AS location, ROW_NUMBER() OVER (PARTITION BY t1.statement ORDER BY l.loc) AS rn FROM Table1 t1 JOIN locations l ON t1.statement ILIKE '%' || l.loc || '%' ) SELECT statement, location FROM matched_results WHERE rn = 1;
这两种方案都比一堆CASE WHEN清爽太多,尤其是方案二,如果你以后要扩展地点列表,直接在CTE里加一行SELECT '新地点'就行,非常方便。
内容的提问来源于stack exchange,提问作者Dela
相关产品推荐
相关产品推荐

