在sql中用大写字母分隔单词

时间:2014-05-05 10:57:00

标签: sql sql-server tsql

有谁知道如何从字符串中以大写字母开头分割单词?

示例:

    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

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

7 个答案:

答案 0 :(得分:17)

这是我创建的一个类似于&#34;删除非字母字符&#34;的函数。 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 :(得分:3)

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

<强>功能

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 ║
╚══════════════════╝

答案 2 :(得分:2)

如果需要单个查询,则可以使用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行

答案 3 :(得分:1)

构建Numbers表。 SO上有一些优秀的帖子向您展示如何做到这一点。使用高于输入字符串最大长度的值填充它。选择从1到当前输入字符串的实际长度的值。将此数字列表交叉连接到输入字符串。将结果用于SUBSTRING()每个字符。然后你可以 将得到的one-charachter值列表与预先填充的表值变量进行比较,使用ASCII()将每个字符转换为整数只选择介于65('A')和90('Z')之间的那些。此时,您有一个列表,它是输入字符串中每个大写字符的位置。 UNION输入字符串到此列表末尾的最大长度。你会在一瞬间看到原因。现在你可以SUBSTRING()输入变量,从行N给出的数字开始,取一个长度(由行N + 1给出的数字) - (行N给出的数字)。这就是为什么你必须UNION最后的额外数字。最后,使用您选择的算法将所有这些子串连接在一起,以空格分隔。

抱歉,我面前没有实例可以试用代码。听起来很有趣。我认为使用嵌套的SELECT语句进行此操作会变得错综复杂且无法维护;更好地将其列为CTE,恕我直言。

答案 4 :(得分:0)

我使用的是ITVF功能(表格功能)。 在性能方面,内联函数的工作方式类似于视图

    CREATE FUNCTION [dbo].[udf_Split_Capitals_In_Str]
    (@str VARCHAR(8000))
    RETURNS TABLE AS RETURN 
    WITH Tally (n) AS
    (
        SELECT TOP (LEN (@str)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
        FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0)) a(n)
        CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(n)
        CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(n)
        CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d(n)

    )
    SELECT New_Str =  STUFF((
        SELECT 
        CASE 
            WHEN SUBSTRING(@str, n,1) = UPPER(SUBSTRING(@str, n,1)) Collate Latin1_General_CS_AI AND n > 1 
            THEN ' ' + SUBSTRING(@str, n,1)  
            ELSE SUBSTRING(@str, n,1) 
        END
    FROM Tally
    FOR XML PATH ('')),1,0,'')

/*How To use:*/
SELECT * FROM dbo.udf_Split_Capitals_In_Str ('HelloWorld')
/*Cross Apply Example*/
    SELECT T.* , Fixed_Name.New_Str FixedName
    FROM 
        (       
        SELECT Id= 1 , Name = 'DonaldTrump'
        UNION ALL 
        SELECT Id= 2 , Name = 'HilaryClinton'
        ) T
    CROSS APPLY dbo.udf_Split_Capitals_In_Str (T.Name) Fixed_Name

答案 5 :(得分:0)

我知道那里已经有了一些很好的答案,但是如果你想避免创建一个函数,你也可以使用递归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 :(得分:0)

请尝试以下操作:

    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)