从字符串中获取大写字母
Posted
技术标签:
【中文标题】从字符串中获取大写字母【英文标题】:Get the Capital letters from a string 【发布时间】:2021-09-12 11:01:20 【问题描述】:我需要从 SQL Server 中的列中提取大写字母。
EX:ABC_DEF_ghi
我只想提取 ABC_DEF。
有时字符串可能类似于 ABC_DEF_GHI_jkl,所以在这种情况下它将是 ABC_DEF_GHI
任何建议都会有所帮助。
提前致谢。
【问题讨论】:
这将是使用正则表达式的小菜一碟。但是 SQL Server 并没有真正的正则表达式支持。我会导出表,在脚本中进行清理,然后重新导入。 您使用的是什么版本的 SQL Server? 这些不仅仅是大写字母,您似乎还需要下划线。 【参考方案1】:正如Tim Biegeleisen 提到的,这在 SQL Server 中并不容易,因为它不支持正则表达式。因此,您必须具备一些创造性。
由于我们不知道您使用的是哪个版本的 SQL Server(尽管 I did ask)我假设您使用的是最新版本的 SQL Server,并且可以访问 @987654325 @ 和 TRIM
。如果没有,您将需要使用旧的 FOR XML PATH
和 STUFF
方法进行字符串聚合,并使用 LTRIM
和 RTRIM
嵌套 REPLACE
s 用于 TRIM
。
无论如何,我在这里所做的是将值整理到一个二进制排序规则中,该排序规则既区分大小写,又按大写和小写顺序排列字母(尽管先小写然后大写的排序规则也可以,这很重要它不是按字母顺序,然后是大小写)。所以按照ABC...Zabc...z
之类的顺序,而不是AaBb...Zz
之类的顺序。然后我使用 Tally 将整理后的字符串拆分为单独的字符。
然后我使用STRING_AGG
和CASE
表达式来只保留下划线字符(您似乎也想要)和大写字母。最后,我使用TRIM
删除任何前导和尾随下划线;如果没有这个,返回的值将是'ABC_DEF_GHI_'
。
我还假设您是针对表而不是标量值执行此操作的,这给出了:
DECLARE @SomeString varchar(100) = 'ABC_DEF_GHI_jkl';
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (SELECT MAX(LEN(V.SomeString)) FROM (VALUES(@SomeString))V(SomeString)) --This would be your table
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2) --100 rows, add more cross joins for more rows
SELECT TRIM('_' FROM STRING_AGG(CASE WHEN SS.C LIKE '[A-Z_]' THEN SS.C END,'') WITHIN GROUP (ORDER BY T.I)) AS NewString
FROM (VALUES(@SomeString))V(SomeString) --This would be your table
CROSS APPLY (VALUES(V.SomeString COLLATE Latin1_General_BIN))C(SomeString) --Collate to a collation that is both case sensitive and orders Uppercase first
JOIN Tally T ON LEN(C.SomeString) >= T.I
CROSS APPLY (VALUES(SUBSTRING(C.SomeString,T.I,1)))SS(C) --Get each character
GROUP BY V.SomeString;
db<>fiddle
当然,“更简单”的解决方案可能是找到并实现 Regex CLR 函数并直接使用它。 ?
原来 OP 使用的是 2014... 这意味着上面需要一些重大的重构。恐怕我不会在这里解释FOR XML PATH
或REPLACE
是如何工作的(因为我将精力投入到原始解决方案中),但是,搜索会为您提供详细信息。:
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (SELECT MAX(LEN(V.SomeString)) FROM (VALUES(@SomeString))V(SomeString)) --This would be your table
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2) --100 rows, add more cross joins for more rows
SELECT REPLACE(LTRIM(RTRIM(REPLACE((SELECT CASE WHEN SS.C LIKE '[A-Z_]' THEN SS.C END
FROM (VALUES(V.SomeString COLLATE Latin1_General_BIN))C(SomeString) --Collate to a collation that is both case sensitive and orders Uppercase first
JOIN Tally T ON LEN(C.SomeString) >= T.I
CROSS APPLY (VALUES(SUBSTRING(C.SomeString,T.I,1)))SS(C) --Get each character
ORDER BY T.I
FOR XML PATH(''),TYPE).value('(./text())[1]','varchar(100)'),'_',' '))),' ','_') AS NewString
FROM (VALUES(@SomeString))V(SomeString) --This would be your table
GROUP BY V.SomeString;
【讨论】:
抱歉耽搁了,我使用的是 SQL Server 2014。 那么你需要使用FOR XML PATH
(和STUFF
)并替换我现在指导的TRIM
函数,@udaykiran。
string_agg for sql server pre 2017 虽然上述内容也需要大量重构。
我已经为你添加了一个 2014 兼容版本,@udaykiran,但请记住标记你正在使用的版本;特别是如果它是不再完全支持的版本。如果没有版本,大多数用户会认为您至少在使用产品的完全受支持的版本,并且很可能会认为您使用的是最新版本。【参考方案2】:
对于 SQL 2017 及更高版本:
DECLARE @SomeString varchar(100) = 'ABC_DEF_GHI_jkl';
WITH T0 AS
(
SELECT 1 AS INDICE,
SUBSTRING(@SomeString, 1, 1) AS RAW_LETTER,
SUBSTRING(UPPER(@SomeString), 1, 1) AS UP_LETTER
UNION ALL
SELECT INDICE + 1,
SUBSTRING(@SomeString, INDICE + 1, 1) AS RAW_LETTER,
SUBSTRING(UPPER(@SomeString), INDICE + 1, 1)
FROM T0
WHERE INDICE < LEN(@SomeString)
)
SELECT STRING_AGG(RAW_LETTER, '') WITHIN GROUP (ORDER BY INDICE)
FROM T0
WHERE RAW_LETTER COLLATE Latin1_General_BIN = UP_LETTER;
对于 2017 年之前的 SQL Server:
WITH T0 AS
(
SELECT 1 AS INDICE,
SUBSTRING(@SomeString, 1, 1) AS RAW_LETTER,
SUBSTRING(UPPER(@SomeString), 1, 1) AS UP_LETTER
UNION ALL
SELECT INDICE + 1,
SUBSTRING(@SomeString, INDICE + 1, 1) AS RAW_LETTER,
SUBSTRING(UPPER(@SomeString), INDICE + 1, 1)
FROM T0
WHERE INDICE < LEN(@SomeString)
)
SELECT STUFF((SELECT '' + RAW_LETTER
FROM T0
WHERE RAW_LETTER COLLATE Latin1_General_BIN = UP_LETTER
ORDER BY INDICE
FOR XML PATH('')), 1, 0, '');
【讨论】:
以上是关于从字符串中获取大写字母的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Pyspark Dataframe 中的字符串列中过滤字母值?