当前位置:首页 > 时尚

sqlsever包含高危地区的地址查询

sqlsever里存着客户表,包含地址字段乱七八糟——有的高危写着“XX省XX市XX区”,有的地区的地直接是“XX路XX号”,还有的址查干脆是“XX村”。但业务方突然甩过来一份高危地区名单,包含要求把所有涉及这些地区的高危记录全捞出来。名单不是地区的地行政区划代码,是址查一堆地名关键词,比如“XX镇XX村”“XX街道XX巷”。包含

直接写WHERE address LIKE '%XX镇XX村%'?高危能跑,但名单里有一百多个地名,地区的地你打算写一百个OR?址查SQL语句长到编辑器都卡,维护的包含人看了想骂娘。更麻烦的高危是,地址里可能藏着“XX镇XX村”的地区的地上级地区,比如“XX省XX市XX镇XX村”,但名单里只给了“XX镇XX村”,LIKE模糊匹配倒是能碰上,可万一地址写成“XX村(XX镇)”呢?格式不统一,LIKE就是碰运气。

换个思路。把高危地名拆成最小颗粒度——镇、村、街道、巷、路,存进临时表,然后和地址字段做多对多匹配。别用LIKE,用CHARINDEX或者PATINDEX,循环遍历每个高危关键词,命中就标记。sqlsever里可以写个存储过程,开个游标,逐条扫描地址,逐词比对。听着笨重,但数据量不大(几千条),跑起来也就几秒钟。

DECLARE @kw NVARCHAR(100) DECLARE cur CURSOR FOR SELECT keyword FROM #high_risk_areas OPEN cur FETCH NEXT FROM cur INTO @kw WHILE @@FETCH_STATUS = 0 BEGIN UPDATE #customers SET is_high_risk = 1 WHERE address LIKE '%' + @kw + '%' FETCH NEXT FROM cur INTO @kw END CLOSE cur DEALLOCATE cur

这段代码有个坑——如果地址字段是NVARCHAR(500),关键词里带括号或者特殊符号,LIKE会误判。比如“XX路(东段)”里的括号,在LIKE模式里是通配符,得用ESCAPE转义。别问我怎么知道的,之前线上查漏了一个“XX路(南)”的记录,就是因为括号被当成分组符号了。

更稳的做法是全文索引。sqlsever的全文搜索能处理分词,但中文分词对地名不友好,“XX镇”可能被拆成“XX”和“镇”,反而查不到。所以别迷信全文索引,对地址这种半结构化数据,老老实实做关键词表,加个CONTAINS或者FREETEXT都行,但前提是你得先把地址清洗成标准格式,比如统一去掉“省”“市”前缀,只保留区县以下部分。

还有个细节——高危地区名单不是一成不变的。今天加一个“XX物流园”,明天删一个“XX旧货市场”。所以别把关键词硬编码在SQL里,建一张配置表,业务方自己维护。查询时动态拼接条件,用EXISTS子查询关联配置表,这样名单一变,查询结果自动跟着变,不用改代码。

最后说下性能。如果你非要在大表(几百万行)上跑这种模糊匹配,那得加索引,但普通索引对LIKE '%xx%'无效。sqlsever的
列存储索引
或者
内存优化表
能缓解,但成本高。实际业务里,高危地区查询通常配合时间范围、客户类型等条件,先把数据集缩小到几千条,再跑关键词匹配,速度可以接受。别一上来就全表扫描,那纯粹是给自己找麻烦。

写这段的时候我特意翻了之前处理过的一个案例——某地警方要求排查某批发市场关联的所有交易记录。地址字段里有“XX批发市场A区12号”,也有“XX批发市场东门临时摊位”。名单里只给了“XX批发市场”。用LIKE '%XX批发市场%'能查出来,但漏了“XX批发市潮”(错别字)或者“XX批市”(简称)。所以清洗数据时,把“市场”“商城”“中心”这类后缀统一化,或者干脆用正则提取核心地名,再匹配。sqlsever 2016以上支持STRING_SPLIT,配合TRANSLATE做字符替换,能省不少事。

别指望一条SQL解决所有问题。真实场景里,地址数据脏得超乎想象,高危名单也总有你没想到的变体。我的建议是:先抽样看数据,列出所有可能的地名写法,再决定匹配策略。如果名单里就十几个关键词,直接写死也没问题;如果几百个,就用临时表加循环。关键是把逻辑写清楚,注释写明白,别让后来人看你的代码像看天书。

分享到: