【问题标题】:Split words with a capital letter in sql在sql中用大写字母拆分单词
【发布时间】:2018-12-18 14:56:47
【问题描述】:

有人知道如何从字符串中拆分以大写字母开头的单词吗?

例子:

    DECLARE @var1 varchar(100) = 'OneTwoThreeFour'
    DECLARE @var2 varchar(100) = 'OneTwoThreeFourFive'
    DECLARE @var3 varchar(100) = 'One'

    SELECT @var1 as Col1, <?> as Col2
    SELECT @var2 as Col1, <?> as Col2
    SELECT @var3 as Col1, <?> as Col2

预期结果:

    Col1                Col2
    OneTwoThreeFour     One Two three Four
    OneTwoThreeFourFive One Two Three Four Five
    One                 One

如果这不可能(或者如果太长),标量函数也可以。

【问题讨论】:

  • 我想可以通过使用正则表达式查找 (A-Z) 并替换为“空格”+ (A-Z) 来完成。注意标量函数可能会消耗性能。
  • @jean SQL Server 中没有正则表达式。
  • This article 概述了一种向 t-sql 添加简单正则表达式支持的方法。性能警告适用。请注意,您可以在 like 运算符的参数中使用简单模式,即。 %[a-z][A-Z]%,用于识别包含驼峰式数据列的记录。
  • 通过正则表达式,我的意思是做任何事情,例如 SELECT patindex('%[ABCDEFGHIJKLMNOPQRSTUVWXYZ]%','gaurang Ahmedab​​ad' COLLATE SQL_Latin1_General_CP1_CS_AS)

标签: sql sql-server tsql


【解决方案1】:

这是我创建的一个类似于“删除非字母字符”的函数。 How to strip all non-alphabetic characters from string in SQL Server?

这个使用区分大小写的排序规则,主动寻找非空格/大写字母组合,然后使用 STUFF 函数插入空格。这是一个标量 UDF,所以有些人会立即说它会比其他解决方案慢。对于这个概念,我说,请测试一下。此函数不使用任何表数据,仅根据需要循环多次,因此它可能会为您提供非常好的性能。

Create Function dbo.Split_On_Upper_Case(@Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin

    Declare @KeepValues as varchar(50)
    Set @KeepValues = '%[^ ][A-Z]%'
    While PatIndex(@KeepValues collate Latin1_General_Bin, @Temp) > 0
        Set @Temp = Stuff(@Temp, PatIndex(@KeepValues collate Latin1_General_Bin, @Temp) + 1, 0, ' ')

    Return @Temp
End

这样称呼它:

Select dbo.Split_On_Upper_Case('OneTwoThreeFour')
Select dbo.Split_On_Upper_Case('OneTwoThreeFour')
Select dbo.Split_On_Upper_Case('One')
Select dbo.Split_On_Upper_Case('OneTwoThree')
Select dbo.Split_On_Upper_Case('stackOverFlow')
Select dbo.Split_On_Upper_Case('StackOverFlow')

【讨论】:

  • 这非常有效。但前提是你有 1 个大写字母。就像“EmailTitle”变成了“Email Title”,这是完美的。但是,如果每个单词有超过 1 个大写字母怎么办。 “EmailGUID”变成“Email G U I D”。而我想要“电子邮件 GUID”将 @KeepValues 替换为:Set @KeepValues = '%[^ A-Z][A-Z]%'
【解决方案2】:

这是我刚刚创建的一个函数。

功能

CREATE FUNCTION dbo.Split_On_Upper_Case
 (
     @String VARCHAR(4000)
 )
RETURNS VARCHAR(4000)
AS
BEGIN

DECLARE @Char CHAR(1);
DECLARE @i    INT = 0;
DECLARE @OutString VARCHAR(4000) = '';


WHILE (@i <= LEN(@String))
BEGIN
    SELECT @Char = SUBSTRING(@String, @i,1)

    IF (@Char = UPPER(@Char) Collate Latin1_General_CS_AI) 
       SET @OutString = @OutString + ' ' + @Char;
    ELSE 
       SET @OutString = @OutString +  @Char;

     SET @i += 1;
END

 SET @OutString =  LTRIM(@OutString);

 RETURN @OutString;

END 

测试数据

DECLARE @TABLE TABLE (Strings VARCHAR(1000))
INSERT INTO @TABLE 
VALUES ('OneTwoThree')   ,
       ('FourFiveSix')   ,
       ('SevenEightNine')

查询

SELECT dbo.Split_On_Upper_Case(Strings) AS Vals
FROM @TABLE

结果集

╔══════════════════╗
║       Vals       ║
╠══════════════════╣
║ One Two Three    ║
║ Four Five Six    ║
║ Seven Eight Nine ║
╚══════════════════╝

【讨论】:

  • 似乎无效。您正在循环通过 varchar 拆分它并逐个字符地将其重新组合在一起。不利于性能。
【解决方案3】:

如果需要单个查询,可以使用 26 REPLACE 来检查每个大写字母,例如

SELECT @var1 col1, REPLACE(
                    REPLACE(
                     REPLACE(
                      ...
                       REPLACE(@var1, 'A', ' A')
                    , ... 
                  , 'X', ' X')
                , 'Y', ' Y')
              , 'Z', ' Z') col2

不是最漂亮的东西,但它会起作用。

编辑
只是为了添加另一个功能以与其他答案不同的方式做同样的事情

CREATE FUNCTION splitCapital (@param Varchar(MAX))
RETURNS Varchar(MAX)
BEGIN
  Declare @ret Varchar(MAX) = '';
  declare @len int = len(@param);

  WITH Base10(N) AS (
              SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 
    UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 
    UNION ALL SELECT 8 UNION ALL SELECT 9
  ), Chars(N) As (
    Select TOP(@len)
           nthChar 
         = substring(@param, u.N + t.N*10 + h.N*100 + th.N*1000 + 1, 1) 
           Collate Latin1_General_CS_AI
    FROM   Base10 u
           CROSS JOIN Base10 t
           CROSS JOIN Base10 h
           CROSS JOIN Base10 th
    WHERE  u.N + t.N*10 + h.N*100 + th.N*1000 < @len
    ORDER BY u.N + t.N*10 + h.N*100 + th.N*1000
  )
  SELECT @ret += Case nthChar 
                      When UPPER(nthChar) Then ' ' 
                      Else '' 
                 End + nthChar
  FROM   Chars

  RETURN @ret;
END

这个使用 TSQL 连接字符串变量的可能性,我不得不使用 TOP N 技巧来强制 Chars CTE 行以正确的顺序排列

【讨论】:

  • @t-clausen.dk Select replace('bBb' COLLATE Latin1_General_CS_AI, 'B', 'B') 返回 'b Bb'
  • 当然不值得投反对票。 +1 让你平衡。
  • @blam 当答案给出错误结果时,它应该被否决
  • @t-clausen.dk 真的,您没有明白需要区分大小写的排序规则。
【解决方案4】:

建立一个数字表。 SO上有一些优秀的帖子向您展示如何做到这一点。用输入字符串最大长度的值填充它。从 1 到当前输入字符串的实际长度中选择值。将此数字列表交叉连接到输入字符串。将结果用于SUBSTRING() 每个字符。然后您可以或者将生成的单字符值列表与预填充的表值变量进行比较使用ASCII() 将每个字符转换为整数并仅选择介于 65 ('A') 和 90 ('Z') 之间的那些。此时您有一个列表,它是输入字符串中每个大写字符的位置。 UNION 输入字符串的最大长度到此列表的末尾。你会在一秒钟内明白为什么。现在您可以SUBSTRING() 您的输入变量,从第 N 行给出的数字开始,长度为(第 N+1 行给出的数字)-(第 N 行给出的数字)。这就是为什么你必须UNION最后的额外号码。最后,使用您选择的算法将所有这些子字符串以空格分隔的方式连接在一起。

抱歉,我面前没有实例来试用代码。听起来是个有趣的任务。我认为使用嵌套的SELECT 语句会变得复杂且不可维护;恕我直言,最好将其布置为 CTE。

【讨论】:

  • 是的,创建这个很有趣,我刚刚创建了一个,看看 :)
  • @M.Ali - 刚才我很欣赏你的回答。我对 OP 的建议是,他将其作为单个 SELECT 进行尝试,利用查询引擎的关系特性并最大限度地减少基于函数的解决方案可能产生的 CROSS APPLY 的任何性能影响。
【解决方案5】:

我知道已经有一些很好的答案,但如果您想避免创建函数,您也可以使用递归 CTE 来完成此操作。这当然不是一种干净的方式,但它确实有效。

DECLARE
    @camelcase nvarchar(4000) = 'ThisIsCamelCased'
;

WITH
    split
AS
    (
        SELECT
              [iteration]   = 0
             ,[string]      = @camelcase

        UNION ALL

        SELECT
             [iteration]    = split.[iteration] + 1
            ,[string]       = STUFF(split.[string], pattern.[index] + 1, 0, ' ')
        FROM
            split
        CROSS APPLY
            ( SELECT [index] = PATINDEX(N'%[^ ][A-Z]%' COLLATE Latin1_General_Bin, split.[string]) )
            pattern
        WHERE
            pattern.[index] > 0
    )
SELECT TOP (1)
    [spaced] = split.[string]
FROM
    split
ORDER BY
    split.[iteration]   DESC
;

正如我所说,这不是编写查询的好方法,但是当我只是编写一些临时查询时,我不想向数据库添加新的工件时,我会使用这样的东西。你也可以使用它来创建你的函数作为内联表值函数,这总是更好一点。

【讨论】:

    【解决方案6】:

    请试试这个:

        declare  @t nvarchar (100) ='IamTheTestString'  
        declare  @len int
        declare  @Counter int =0 
        declare  @Final nvarchar (100) =''
        set @len =len( @t)
    
    
        while (@Counter <= @len)
        begin 
    
        set @Final= @Final + Case when  ascii(substring (@t,@Counter,1))>=65 and  
        ascii(substring (@t,@Counter,1))<=90 then ' '+substring (@t,@Counter,1) else 
        substring (@t,@Counter,1) end
    
    
        set @Counter=@Counter+1
        end
    
        print ltrim(@Final)
    

    【讨论】:

      猜你喜欢
      • 2015-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-06
      • 1970-01-01
      • 2012-04-28
      • 2012-04-21
      • 1970-01-01
      相关资源
      最近更新 更多