Sql server 规范化大写字符串,但保持括号中的内容不变

Sql server 规范化大写字符串,但保持括号中的内容不变,sql-server,function,stored-procedures,Sql Server,Function,Stored Procedures,我有一段文本,我希望在数据库中对字符串进行适当的大小写,但我遇到了一个问题,我正在使用适当的存储过程 WITH -- your input indata(s) AS ( SELECT 'TEST DATA (BA1)' UNION ALL SELECT 'TEST DATA 2 (BA2)' UNION ALL SELECT 'TEST DATA 3 (BA3)' ) , -- add an identifier, which you need for grouping la

我有一段文本,我希望在数据库中对字符串进行适当的大小写,但我遇到了一个问题,我正在使用适当的存储过程

WITH
-- your input
indata(s) AS (
          SELECT 'TEST DATA (BA1)'
UNION ALL SELECT 'TEST DATA 2 (BA2)'
UNION ALL SELECT 'TEST DATA 3 (BA3)'
)
,
-- add an identifier, which you need for grouping later ...
w_id AS (
  SELECT
    ROW_NUMBER() OVER(ORDER BY s) AS id
  , *
  FROM indata
)
, 
-- "explode" into one row per space delimited sub-string using STRING_SPLIT() ...
words AS (
  SELECT 
   id
  ,value
  FROM w_id
  CROSS APPLY STRING_SPLIT(s,' ')
)
,
-- check if the "value" you got begins with a left paren 
-- and ends with a right paren, and proceed accordingly ...
right_case AS (
  SELECT
    id
  , CASE WHEN LEFT(value,1) <> '(' AND RIGHT(value,1) <> ')'
      THEN UPPER(LEFT(value,1))+LOWER(RIGHT(value,LEN(value)-1))
      ELSE value
    END AS val
  FROM words
)
-- finally, re-aggregate all together ...
SELECT
  STRING_AGG(val,' ') AS s
FROM right_case
GROUP BY id;

s
Test Data (BA1)
Test Data 2 (BA2)
Test Data 3 (BA3)
为了解决下面的问题,我需要我的函数用ToUpper-sow修复括号中的内容。我正在使用SQL Server 2017

我试过下面的方法。但问题是我有如下数据

我希望我的程序是在一个功能,我可以重用。这也需要在2016年起作用

TEST DATA (BA1) 
TEST DATA 2 (BA2) 
TEST DATA 3 (BA3)
它应该会回来

Test Data (BA1) 
Test Data 2 (BA2) 
Test Data 3 (BA3)
但是,它却回来了:

Test Data (Ba1) 
Test Data 2 (Ba2) 
Test Data 3 (Ba3)
你知道怎样才能阻止它变成小写吗?因此,我的意思是,左括号和右括号中的内容应该保持大写,或者变成大写

当它进入括号时,问题就来了,它也使括号变为小写。我希望我的函数忽略括号内的文本

IF OBJECT_ID('dbo.ProperCase') IS NOT NULL
    DROP FUNCTION dbo.ProperCase
GO

CREATE FUNCTION dbo.PROPERCASE 
     (@str VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
    SET @str = ' ' + @str
    SET @str = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @str, ' a', ' A'), ' b', ' B'), ' c', ' C'), ' d', ' D'), ' e', ' E'), ' f', ' F'), ' g', ' G'), ' h', ' H'), ' i', ' I'), ' j', ' J'), ' k', ' K'), ' l', ' L'), ' m', ' M'), ' n', ' N'), ' o', ' O'), ' p', ' P'), ' q', ' Q'), ' r', ' R'), ' s', ' S'), ' t', ' T'), ' u', ' U'), ' v', ' V'), ' w', ' W'), ' x', ' X'), ' y', ' Y'), ' z', ' Z')
    RETURN RIGHT(@str, LEN(@str) - 1)
END
GO
编辑2

我也尝试了下面这个伟大的答案,但结果是一样的

1行受影响消息537,级别16,状态3,第4行无效长度 传递给LEFT或SUBSTRING函数的参数


如果你知道你只有一组帕伦,这是在最后,你可以分割字符串,大小写正确的第一部分和glom回第二部分。大概是这样的:

BEGIN
    SET @newstr = ' ' + LEFT(@str, CHARINDEX('(', @str);
    SET @newstr = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @str, ' a', ' A'), ' b', ' B'), ' c', ' C'), ' d', ' D'), ' e', ' E'), ' f', ' F'), ' g', ' G'), ' h', ' H'), ' i', ' I'), ' j', ' J'), ' k', ' K'), ' l', ' L'), ' m', ' M'), ' n', ' N'), ' o', ' O'), ' p', ' P'), ' q', ' Q'), ' r', ' R'), ' s', ' S'), ' t', ' T'), ' u', ' U'), ' v', ' V'), ' w', ' W'), ' x', ' X'), ' y', ' Y'), ' z', ' Z')
    RETURN STUFF(@newstr, 1, 1, '') + RIGHT(@str, CHARINDEX('(', REVERSE(@str))
END;
注意:这是一个非常具体的答案,根据您所陈述的输入来破解您当前的函数


一般来说,我建议您重写函数以逐个字符循环字符串,这样您就可以跟踪多个括号表达式。

您只需使用SQL即可,无需任何过程

WITH
-- your input
indata(s) AS (
          SELECT 'TEST DATA (BA1)'
UNION ALL SELECT 'TEST DATA 2 (BA2)'
UNION ALL SELECT 'TEST DATA 3 (BA3)'
)
,
-- add an identifier, which you need for grouping later ...
w_id AS (
  SELECT
    ROW_NUMBER() OVER(ORDER BY s) AS id
  , *
  FROM indata
)
, 
-- "explode" into one row per space delimited sub-string using STRING_SPLIT() ...
words AS (
  SELECT 
   id
  ,value
  FROM w_id
  CROSS APPLY STRING_SPLIT(s,' ')
)
,
-- check if the "value" you got begins with a left paren 
-- and ends with a right paren, and proceed accordingly ...
right_case AS (
  SELECT
    id
  , CASE WHEN LEFT(value,1) <> '(' AND RIGHT(value,1) <> ')'
      THEN UPPER(LEFT(value,1))+LOWER(RIGHT(value,LEN(value)-1))
      ELSE value
    END AS val
  FROM words
)
-- finally, re-aggregate all together ...
SELECT
  STRING_AGG(val,' ') AS s
FROM right_case
GROUP BY id;

s
Test Data (BA1)
Test Data 2 (BA2)
Test Data 3 (BA3)

这不是一个理想的解决方案,但它似乎有效。我在这里使用了两个内联表值函数。标量函数不倾向于在任何地方执行内联表值函数,尽管2019支持标量内联,但您正在使用2017

首先,您需要获取的副本,因为我们需要一个支持序号位置的拆分器,而STRING_SPLIT不支持序号位置。然后我们可以使用一些加窗求和来检查括号的计数。如果我们是积极的,那么我们是在括号内,不应该应用适当的套管。我还假设括号后面可能有数据,否则这实际上更容易:这给出了以下内容:

使用沙箱; 去 创建或更改函数dbo.ProperCase@String varchar8000 返回表 作为回报 拆分为 选择DS.ItemNumber, DS.项目:, SUMCASE CHARINDEX,DS.Item当0然后0 ELSE 1结束订单时,DS.ItemNumber ASC行位于无界的前一行和当前行之间- ISNULLSUMCASE CHARINDEX,DS.Item当0然后0 ELSE 1以DS.ItemNumber ASC行结束订单,在无界的前一行和前一行之间,0作为内帧 来自dbo.dsplit8k_LEAD@String,''DS 选择字符串\u AGGCASE S.infrackets WHEN 0,然后选择STUFFLOWERS.Item,1,1,UPPERLEFTS.Item,1 ELSE S.Item END“”,在按S.ItemNumber作为新闻字符串的组订单中 从分裂到分裂; 去 挑选* 根据“测试数据BA1”的值, “测试数据2 BA2”, “测试数据3 BA3”, “测试数据4 BA4测试”VYourString 交叉应用dbo.ProperCaseV.YourString; 去
我想你需要一个while循环来循环字符串,跟踪逻辑。@GordonLinoff请参见上面的编辑我也尝试过使用另一个函数,但没有成功,它仍然使括号变为小写,我使用CLR函数来实现这一点,因为C语言中的这些复杂字符串操作要容易得多。请参见我的编辑2我想使用的函数越多,我也会这样做喜欢将它作为一个可用于其他工作的函数当一个人询问某个过程时,他们通常希望它作为一个过程或函数,而不是一个普通的sql语句。这仍然意味着你应该考虑我的原始functions@rogue39nin通常可以将SQL语句转换为过程上的函数;我对sql 13.05版有一个问题,说STRING_AGG不受支持。我可以使用的其他任何东西我的生产数据库版本必须早于2017年。当他们没有左括号或右括号时,它可以工作吗?当他们没有左括号或右括号时,我收到一个错误。你收到了什么错误?它没有为我生成一个。为什么你要使用FROM dbo.DelimitedSplit8K_LEAD im不在我的任何函数中。。。首先,从@rogue39nin的答案中,您需要获取DelimitedSplit8K_LEAD的副本,因为我们需要一个支持序号位置的拆分器,而STRING_SPLIT不支持序号位置。您可以这样做,@rogue39nin。。。从{Table}{Alias}交叉应用dbo.ProperCase{Alias}.{Column}PC;更新{Alias}SET{Column}=PC.NewString;。。。这也没什么不同,我会告诉你如何在上面的答案中引用函数
BEGIN
    SET @newstr = ' ' + LEFT(@str, CHARINDEX('(', @str);
    SET @newstr = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @str, ' a', ' A'), ' b', ' B'), ' c', ' C'), ' d', ' D'), ' e', ' E'), ' f', ' F'), ' g', ' G'), ' h', ' H'), ' i', ' I'), ' j', ' J'), ' k', ' K'), ' l', ' L'), ' m', ' M'), ' n', ' N'), ' o', ' O'), ' p', ' P'), ' q', ' Q'), ' r', ' R'), ' s', ' S'), ' t', ' T'), ' u', ' U'), ' v', ' V'), ' w', ' W'), ' x', ' X'), ' y', ' Y'), ' z', ' Z')
    RETURN STUFF(@newstr, 1, 1, '') + RIGHT(@str, CHARINDEX('(', REVERSE(@str))
END;
WITH
-- your input
indata(s) AS (
          SELECT 'TEST DATA (BA1)'
UNION ALL SELECT 'TEST DATA 2 (BA2)'
UNION ALL SELECT 'TEST DATA 3 (BA3)'
)
,
-- add an identifier, which you need for grouping later ...
w_id AS (
  SELECT
    ROW_NUMBER() OVER(ORDER BY s) AS id
  , *
  FROM indata
)
, 
-- "explode" into one row per space delimited sub-string using STRING_SPLIT() ...
words AS (
  SELECT 
   id
  ,value
  FROM w_id
  CROSS APPLY STRING_SPLIT(s,' ')
)
,
-- check if the "value" you got begins with a left paren 
-- and ends with a right paren, and proceed accordingly ...
right_case AS (
  SELECT
    id
  , CASE WHEN LEFT(value,1) <> '(' AND RIGHT(value,1) <> ')'
      THEN UPPER(LEFT(value,1))+LOWER(RIGHT(value,LEN(value)-1))
      ELSE value
    END AS val
  FROM words
)
-- finally, re-aggregate all together ...
SELECT
  STRING_AGG(val,' ') AS s
FROM right_case
GROUP BY id;

s
Test Data (BA1)
Test Data 2 (BA2)
Test Data 3 (BA3)