如何基于列中字符串位置匹配,查询特定产品试用客户?
基于逗号分隔字符串筛选试用客户的SQL实现
问题场景
现有一个聚合客户数据的视图,结构及数据如下:
+----------+----------+-----------------------+ | customer | products | products_trial_status | +----------+----------+-----------------------+ | 234253 | A,B,C | false,true,false | | 923403 | A,C | true,true | | 123483 | B | true | | 239874 | B,C | false,false | +----------+----------+-----------------------+
需求是编写查询语句,返回使用特定产品且处于试用状态的客户列表。例如查询产品B的试用客户,预期结果为:
+----------+ | customer | +----------+ | 234253 | | 123483 | +----------+
已知核心思路是匹配目标产品在products列中的位置,再验证products_trial_status列对应位置的值为true,且无法修改现有字符串存储格式,必须基于当前结构解决。
解决方案
不同数据库的字符串处理函数存在差异,以下是主流数据库的实现方式:
1. MySQL/MariaDB 实现
利用FIND_IN_SET获取产品位置,结合SUBSTRING_INDEX提取对应试用状态:
SELECT customer FROM your_view_name WHERE FIND_IN_SET('B', products) > 0 AND SUBSTRING_INDEX( SUBSTRING_INDEX(products_trial_status, ',', FIND_IN_SET('B', products)), ',', -1 ) = 'true';
逻辑说明:
FIND_IN_SET('B', products)返回产品B在逗号分隔字符串中的位置(从1开始计数,不存在则返回0)- 内层
SUBSTRING_INDEX截取到目标位置前的所有内容,外层SUBSTRING_INDEX提取最后一个元素,即对应位置的试用状态
2. PostgreSQL 实现
通过string_to_array将字符串转为数组,利用数组索引匹配对应状态:
SELECT customer FROM your_view_name WHERE 'B' = ANY(string_to_array(products, ',')) AND (string_to_array(products_trial_status, ','))[array_position(string_to_array(products, ','), 'B')] = 'true';
逻辑说明:
string_to_array将逗号分隔字符串转为数组,'B' = ANY(...)判断产品B是否存在array_position获取产品B在数组中的位置,再用该索引提取试用状态数组对应位置的值进行判断
3. SQL Server 实现
提供两种实现方式,其中拆分关联的方式更清晰:
方式一:字符串直接匹配
SELECT customer FROM your_view_name WHERE CHARINDEX(',B,', ',' + products + ',') > 0 AND SUBSTRING( ',' + products_trial_status + ',', CHARINDEX(',B,', ',' + products + ','), LEN(',true,') ) = ',true,';
逻辑说明:在字符串前后加逗号,避免产品B在开头/结尾的边界匹配问题,通过位置截取对应试用状态进行匹配
方式二:拆分后关联
WITH customer_products AS ( SELECT customer, value AS product, ROW_NUMBER() OVER (PARTITION BY customer ORDER BY (SELECT NULL)) AS rn FROM your_view_name CROSS APPLY STRING_SPLIT(products, ',') ), customer_trial_status AS ( SELECT customer, value AS trial_status, ROW_NUMBER() OVER (PARTITION BY customer ORDER BY (SELECT NULL)) AS rn FROM your_view_name CROSS APPLY STRING_SPLIT(products_trial_status, ',') ) SELECT cp.customer FROM customer_products cp JOIN customer_trial_status cts ON cp.customer = cts.customer AND cp.rn = cts.rn WHERE cp.product = 'B' AND cts.trial_status = 'true';
逻辑说明:分别拆分产品和试用状态字符串,添加行号关联对应位置,再筛选目标产品和试用状态
内容的提问来源于stack exchange,提问作者أُكَاتِبُ
相关产品推荐
相关产品推荐

