如何提取字符串中第一个连字符后至第三个连字符前的内容?
问题分析与解决方案
先拆解你拿到的SQL原理,再给出满足需求的查询方法。
原SQL查询原理拆解
你提供的查询里,Example1是提取字符串最后一个.后的后缀(比如24XX4),Example2原本要提取倒数第二个-到最后一个-之间的内容(比如LMNO),但代码存在多余的无效操作,具体步骤:
对于Example1(提取24XX4):
REVERSE([Code]):把整个字符串反转,比如EXAMPLE-ABC-1234-XYZZ-DE-LMNO.24XX4反转后变成4XX42.ONML-ED-ZZYX-4321-CBA-ELPMAXEREPLACE(reverse([Code]), '.', '.'):这一步完全多余,替换相同字符没有任何作用,属于笔误PARSENAME(..., 1):PARSENAME是SQL Server用于拆分对象名(如数据库.表.列)的函数,默认按.分隔,取从右往左数第1段,这里就是4XX42REVERSE(...):把4XX42反转回原顺序,得到24XX4
对于Example2(原本要提取LMNO):
代码里的REPLACE(REVERSE([Code]), '-', '-')同样多余,正确写法应该是把-替换成.,让反转后的字符串被.分隔成多段,再用PARSENAME取第2段,反转后得到LMNO。
满足你需求的查询方法
你需要提取第一个-后、第三个-前的内容(比如ABC-1234),这里提供两种可靠实现:
方法一:SUBSTRING+CHARINDEX嵌套(兼容所有SQL Server版本)
通过多次调用CHARINDEX定位三个-的位置,再用SUBSTRING截取目标区间:
SELECT code, SUBSTRING( Code, CHARINDEX('-', Code) + 1, CHARINDEX('-', Code, CHARINDEX('-', Code, CHARINDEX('-', Code) + 1) + 1) - (CHARINDEX('-', Code) + 1) ) AS TargetContent FROM [table].[database].[example] WHERE code IN ('EXAMPLE-ABC-1234-XYZZ-DE-LMNO.24XX4', 'EXAMPLE-CBA-1234-XYZZ-DE-LMNO.24XX4')
如果觉得嵌套复杂,可用CROSS APPLY提前计算-的位置,让代码更清晰:
SELECT code, SUBSTRING(Code, pos1 + 1, pos3 - pos1 - 1) AS TargetContent FROM [table].[database].[example] CROSS APPLY ( SELECT CHARINDEX('-', Code) AS pos1, CHARINDEX('-', Code, CHARINDEX('-', Code)+1) AS pos2, CHARINDEX('-', Code, CHARINDEX('-', Code, CHARINDEX('-', Code)+1)+1) AS pos3 ) AS positions WHERE code IN ('EXAMPLE-ABC-1234-XYZZ-DE-LMNO.24XX4', 'EXAMPLE-CBA-1234-XYZZ-DE-LMNO.24XX4')
方法二:STRING_SPLIT(SQL Server 2016+)
如果你的SQL Server版本支持STRING_SPLIT,可按-拆分字符串后,取第2、3段拼接:
SQL Server 2022及以上(支持ordinal参数,保证顺序):
SELECT code, CONCAT(MAX(CASE WHEN ordinal = 2 THEN value END), '-', MAX(CASE WHEN ordinal = 3 THEN value END)) AS TargetContent FROM [table].[database].[example] CROSS APPLY STRING_SPLIT(Code, '-', 1) WHERE code IN ('EXAMPLE-ABC-1234-XYZZ-DE-LMNO.24XX4', 'EXAMPLE-CBA-1234-XYZZ-DE-LMNO.24XX4') GROUP BY code
SQL Server 2016-2019(无ordinal参数,用ROW_NUMBER生成序号):
SELECT code, CONCAT(MAX(CASE WHEN rn = 2 THEN value END), '-', MAX(CASE WHEN rn = 3 THEN value END)) AS TargetContent FROM [table].[database].[example] CROSS APPLY ( SELECT value, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS rn FROM STRING_SPLIT(Code, '-') ) AS split WHERE code IN ('EXAMPLE-ABC-1234-XYZZ-DE-LMNO.24XX4', 'EXAMPLE-CBA-1234-XYZZ-DE-LMNO.24XX4') GROUP BY code
关于PARSENAME的适用性
PARSENAME最多只能处理4个分隔段,且是从右往左计数,你的字符串按-拆分后段数超过4,且目标内容在左侧,用PARSENAME实现会依赖固定段数,一旦字符串结构变化就会出错,不推荐用它来实现你的需求。
内容的提问来源于stack exchange,提问作者Skyei
相关产品推荐
相关产品推荐

