为了它……
此解决方案不同于所有早期的解决方案,即:
- 无需创建函数
- 无需使用模式匹配
- 不需要临时表
- 此解决方案使用递归公用表表达式 (CTE)
但首先 - 请注意,问题并未指定此类字符串的存储位置。在下面的解决方案中,我创建了一个 CTE 作为将这些字符串放入某种“源表”的快速而肮脏的方式。
还要注意 - 此解决方案使用 recursive common table expression (CTE) - 所以不要对这里使用两个 CTE 感到困惑。第一个只是使数据可用于解决方案 - 但解决此问题只需要第二个 CTE。您可以调整代码以使第二个 CTE 查询您现有的表、视图等。
最后 - 我的编码很冗长,尝试使用列和 CTE 名称来解释正在发生的事情,您也许可以稍微简化这个解决方案。我添加了一些伪电话号码,并带有一些(预期的和非典型的,视情况而定)格式,以获取乐趣。
with SOURCE_TABLE as (
select '003Preliminary Examination Plan' as numberString
union all select 'Coordination005' as numberString
union all select 'Balance1000sheet' as numberString
union all select '1300 456 678' as numberString
union all select '(012) 995 8322 ' as numberString
union all select '073263 6122,' as numberString
),
FIRST_CHAR_PROCESSED as (
select
len(numberString) as currentStringLength,
isNull(cast(try_cast(replace(left(numberString, 1),' ','z') as tinyint) as nvarchar),'') as firstCharAsNumeric,
cast(isNull(cast(try_cast(nullIf(left(numberString, 1),'') as tinyint) as nvarchar),'') as nvarchar(4000)) as newString,
cast(substring(numberString,2,len(numberString)) as nvarchar) as remainingString
from SOURCE_TABLE
union all
select
len(remainingString) as currentStringLength,
cast(try_cast(replace(left(remainingString, 1),' ','z') as tinyint) as nvarchar) as firstCharAsNumeric,
cast(isNull(newString,'') as nvarchar(3999)) + isNull(cast(try_cast(nullIf(left(remainingString, 1),'') as tinyint) as nvarchar(1)),'') as newString,
substring(remainingString,2,len(remainingString)) as remainingString
from FIRST_CHAR_PROCESSED fcp2
where fcp2.currentStringLength > 1
)
select
newString
,* -- comment this out when required
from FIRST_CHAR_PROCESSED
where currentStringLength = 1
那么这里发生了什么?
基本上,在我们的 CTE 中,我们选择第一个字符并使用 try_cast (see docs) 将其转换为 tinyint(对于一位数字来说,这是一个足够大的数据类型)。请注意,SQL Server 中的类型转换规则说空字符串(或空格,就此而言)将解析为零,因此添加 nullif 以强制空格和空字符串解析为 null (see discussion )(否则,只要在源数据中遇到空格,我们的结果就会包含一个零字符)。
CTE 还返回第一个字符之后的所有内容 - 这成为我们对 CTE 的递归调用的输入;换句话说:现在让我们处理下一个字符。
最后,CTE 中的字段newString 是通过连接生成的(在第二个SELECT 中)。在任何给定列的两个 SELECT 语句之间使用递归 CTE the data type must match - 包括列大小。因为我们知道我们正在添加(最多)一个字符,所以我们将该字符转换为 nvarchar(1),并将newString(到目前为止)转换为 nvarchar(3999)。连接起来,结果将是 nvarchar(4000) - 匹配我们在第一个 SELECT 中执行的类型转换。
如果您运行此查询并排除 WHERE 子句,您将了解发生了什么 - 但行的顺序可能很奇怪。 (您不一定会看到与单个输入值相关的所有行组合在一起 - 但您仍然应该能够关注)。
希望这是一个有趣的选项,可以帮助一些想要严格基于表达式的解决方案的人。