在适当的情况下将正确的大小写转换为空格 - SQL Server

时间:2016-12-19 08:17:33

标签: sql sql-server tsql

我们在适当的情况下拥有庞大的属性列表,我们希望在每个单词之后获得适当空间的输出

例如 -

按原样: ServiceProviderReferenceNumber

未来:服务提供商参考编号

关于如何在T-SQL中转换它的任何想法?任何帮助将不胜感激

注意:我们正在使用SQL Server 2016

5 个答案:

答案 0 :(得分:4)

试试这个工作

Create Function dbo.Split_On_Upper_Case(@Temp VarChar(100))
Returns VarChar(100)
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

答案 1 :(得分:3)

这是一种没有循环的方法......

除了事实之外,这些循环是要避免的,这使得完整表的处理非常容易。

首先,我创建一个带有三个字符串的模拟

DECLARE @tbl TABLE(ID INT IDENTITY,YourString VARCHAR(100));
INSERT INTO @tbl VALUES('ServiceProviderReferenceNumber'),('SomeOther'),('AndOneMore');

查询将首先创建一个数字计数表,然后将字符串拆分为单个字符,检查大写字母并添加空格。

最后,这会被重新调整和修剪

注意如果您可能需要超过1000个字符,只需向,Numbers AS c添加一个Tally(然后提供10.000个数字)

WITH Numbers AS
 (SELECT Nr FROM(SELECT Nr FROM(VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) AS x(Nr)) AS y)
,Tally AS
(
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Nr
    FROM Numbers,Numbers AS a,Numbers AS b
)
,Splitted AS
(
    SELECT ID 
          ,CASE WHEN ASCII(Chars.OneChar) BETWEEN ASCII('A') AND ASCII('Z') THEN ' ' + Chars.OneChar ELSE Chars.OneChar END AS TheChar
    FROM @tbl AS t
    CROSS APPLY (SELECT TOP(LEN(t.YourString)) Tally.Nr FROM Tally) AS Nmbr
    CROSS APPLY (SELECT SUBSTRING(t.YourString,Nmbr.Nr,1) AS OneChar) AS Chars
)
SELECT ID
      ,LTRIM((
        SELECT s.TheChar AS [*]
        FROM Splitted AS s
        WHERE s.ID=Splitted.ID
        FOR XML PATH('')
       )) AS ReConcatenated
FROM Splitted
GROUP BY ID

结果

1   Service Provider Reference Number
2   Some Other
3   And One More

更新 ad-hoc 循环的比较

CREATE DATABASE testDB;
GO

USE testDB;
GO

CREATE TABLE tbl(ID INT IDENTITY,YourString VARCHAR(100));
GO

CREATE FUNCTION dbo.TestF(@String VARCHAR(4000))
RETURNS VARCHAR(4000)
AS
BEGIN
    DECLARE @StringNew nvarchar(100) = '';
    DECLARE @Char nvarchar(1);
    DECLARE @len int = LEN(@String);
    DECLARE @i int = 0;

    WHILE @i <= @len
      BEGIN
        SET @i = @i+1;
        SET @Char = substring(@String,@i,1);

        IF (UNICODE(@Char) = UNICODE(UPPER(@Char)) AND @i > 1)
          SET @StringNew = @StringNew + ' ' + @Char;
        ELSE
          SET @StringNew = @StringNew + @Char;
      END;

      RETURN @StringNew
    END
GO

INSERT INTO tbl VALUES('ServiceProviderReferenceNumber'),('SomeOther'),('AndOneMore');
GO 100000

DECLARE @d DATETIME=GETDATE();

WITH Numbers AS
 (SELECT Nr FROM(SELECT Nr FROM(VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) AS x(Nr)) AS y)
,Tally AS
(
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Nr
    FROM Numbers,Numbers AS a,Numbers AS b
)
,Splitted AS
(
    SELECT ID 
          ,CASE WHEN ASCII(Chars.OneChar) BETWEEN ASCII('A') AND ASCII('Z') THEN ' ' + Chars.OneChar ELSE Chars.OneChar END AS TheChar
    FROM tbl AS t
    CROSS APPLY (SELECT TOP(LEN(t.YourString)) Tally.Nr FROM Tally) AS Nmbr
    CROSS APPLY (SELECT SUBSTRING(t.YourString,Nmbr.Nr,1) AS OneChar) AS Chars
)
SELECT ID
      ,LTRIM((
        SELECT s.TheChar AS [*]
        FROM Splitted AS s
        WHERE s.ID=Splitted.ID
        FOR XML PATH('')
       )) AS ReConcatenated
FROM Splitted
GROUP BY ID;

SELECT CAST(GETDATE()-@d AS TIME);
GO

DECLARE @d DATETIME=GETDATE();

SELECT ID,dbo.TestF(tbl.YourString) AS ReConcatenated
FROM tbl

SELECT CAST(GETDATE()-@d AS TIME);
GO
USE master;
GO
DROP DATABASE testDB;

结果

**ad-hoc** 2.66 Seconds
**loop**   5.33

更新2:This answer by @sai bharath更快......

结果

**ad-hoc**              2.66 Seconds
**loop**                5.33
**while with `STUFF`**  1.71

答案 2 :(得分:1)

这是一种方法,它循环遍历字符串并比较字符的Uncicode值。我选择比较数字而不是字符,因为根据数据库配置'a'='A'评估为真。

DECLARE @String nvarchar(100) = 'ServiceProviderReferenceNumber';
DECLARE @StringNew nvarchar(100) = '';
DECLARE @Char nvarchar(1);
DECLARE @len int = LEN(@String);
DECLARE @i int = 0;

WHILE @i <= @len
  BEGIN
    SET @i = @i+1;
    SET @Char = substring(@String,@i,1);

    IF (UNICODE(@Char) = UNICODE(UPPER(@Char)) AND @i > 1)
      SET @StringNew = @StringNew + ' ' + @Char;
    ELSE
      SET @StringNew = @StringNew + @Char;
  END;

  PRINT @StringNew

答案 3 :(得分:0)

尝试这种超高速递归CTE

;with
w as (
    select 
        id, 
        cast(YourColumn collate LATIN1_GENERAL_BIN as varchar(500)) ss 
    from YourTable w
),
r as (
    select id, ss s, 2 l, PATINDEX('%[A-Z]%', ss) p, 1 i
    from w

    union all
    select w.id, cast(stuff(s, p, 0, ' ') as varchar(500)), p + 1 l, pos + p + 1 p, pos i
    from w
    join (
        select id, s, PATINDEX('%[A-Z]%', substring(s, p+1, 500) ) pos, p, i
        from r
    ) rr on w.id = rr.id and i>0
)
select id, s
from r
where i=0
OPTION (MAXRECURSION 500); 

答案 4 :(得分:0)

    ;WITH a(s) AS 
    (
     SELECT 'ServiceProviderReferenceNumber' UNION 
     SELECT 'ConvertProperCaseToSpaceAfterProperCase' 
    )
    SELECT LTRIM(b.ss) FROM a
    CROSS APPLY (
        SELECT CASE WHEN ASCII(SUBSTRING(a.s,sv.number,1))  BETWEEN 65 AND 90 THEN ' '+SUBSTRING(a.s,sv.number,1) ELSE SUBSTRING(a.s,sv.number,1) END 
        FROM master.dbo.spt_values AS sv 
        WHERE sv.type='P' AND sv.number BETWEEN 1 AND LEN(a.s)
        FOR XML PATH('')

    ) b(ss)
Convert Proper Case To Space After Proper Case
Service Provider Reference Number