在SQL中返回某列中所有大写的值

3
我有一些字段的值既包含大写字母又包含小写字母。我想要分别返回只有大写字母和只有小写字母的结果,而不是将它们相互转换。我无法找到可用的语句来实现这一点,“SUBSTRING”仅会返回我指定的值,例如第一个和最后一个字符。所以,举个例子,如果我的值为AAbbCCdd并且想要返回大写字母,那么我需要的结果是AACC。

1
在SQL中没有简单的方法来做到这一点 - 在前端语言中有简单的方法来做到这一点。您确定需要在服务器端执行此操作吗? - Hogan
我不明白你的问题。你想从单列中提取大写字母吗?还是你想返回列中所有字母都是大写的值? - Gordon Linoff
1
这是一个相当奇怪的要求。这样做可能有什么可能的实际用途呢?在SQL中这并不容易(至少不快)。 - Sean Lange
@popovitsj 不是真的 - http://msdn.microsoft.com/en-us/magazine/cc163473.aspx - 但这并不容易,但可能是解决这个要求的方法。 - Hogan
你可能需要编写一个存储过程来完成这个任务。这篇文章可能会有所帮助:test-for-upper-case-t-sql - StevieG
显示剩余5条评论
3个回答

2
使用函数:
CREATE FUNCTION [dbo].[GetCased](@BUFFER VARCHAR(MAX), @GETUPPER BIT) RETURNS VARCHAR(MAX) AS
BEGIN
    DECLARE @LEN INT = LEN(@BUFFER), @POS INT = 1, @CHAR CHAR(1), @RESULT VARCHAR(MAX) = ''
    WHILE @POS <= @LEN BEGIN
        SET @CHAR = SUBSTRING(@BUFFER, @POS, 1)
        SET @RESULT += CASE WHEN @CHAR COLLATE Latin1_General_CS_AS = 
            CASE WHEN @GETUPPER = 1 THEN UPPER(@CHAR) ELSE LOWER(@CHAR) END COLLATE Latin1_General_CS_AS THEN @CHAR ELSE '' END
        SET @POS += 1
    END
    RETURN @RESULT
END

... 

select
  dbo.GetCased('AAbbCCdd', 1) as 'all upper',
  dbo.GetCased('AAbbCCdd', 0) as 'all lower'

或者

CREATE FUNCTION [dbo].[fnRemovePatternFromString](@BUFFER VARCHAR(MAX), @PATTERN VARCHAR(128)) RETURNS VARCHAR(MAX) AS
BEGIN
    DECLARE @POS INT = PATINDEX(@PATTERN, @BUFFER COLLATE Latin1_General_CS_AS)
    WHILE @POS > 0 BEGIN
        SET @BUFFER = STUFF(@BUFFER, @POS, 1, '')
        SET @POS = PATINDEX(@PATTERN, @BUFFER COLLATE Latin1_General_CS_AS)
    END
    RETURN @BUFFER
END

...

select
  dbo.fnRemovePatternFromString('AAbbCCdd ', '%[ABCDEFGHIJKLMNOPQRSTUVWXYZ]%') as 'all lower'
  dbo.fnRemovePatternFromString('AAbbCCdd ', '%[abcdefghijklmnopqrstuvwxyz]%') as 'all upper'

不能使用[a-z]


1
这是另一种使用函数的方法:

CREATE FUNCTION [dbo].returnUppers
    (
      @str AS varchar(Max)
    )
RETURNS varchar(MAX)
AS
    BEGIN
        DECLARE @len INT
        DECLARE @cc INT = 1
        DECLARE @return VARCHAR(MAX) = ''

        SELECT @len = LEN(@str)

        WHILE @len >= @cc
            BEGIN
                IF UPPER(SUBSTRING(@str,@cc,1)) = SUBSTRING(@str,@cc,1) COLLATE sql_latin1_general_cp1_cs_as
                    SELECT @return = @return + SUBSTRING(@str,@cc,1)
                SET @cc += 1
            END

        RETURN @return
    END
GO

使用方法:

DECLARE @string VARCHAR(20) = 'AAbbCCdd'
SELECT dbo.returnUppers(@string)

返回AACC。您需要编写一个类似的函数来转换小写,只需将UPPER()更改为LOWER()


0

正如评论中提到的那样 - 这应该在表示层中完成,而不是在 SQL 中。

然而,这并不能阻止它成为一种乐趣!

关键是使用区分大小写的排序规则。在这个例子中,我选择了 SQL_Latin1_General_CP1_CS_AS("CS" = 区分大小写,"CI" = 不区分大小写)

然而,这种解决方案涉及循环(在这种情况下是递归 CTE),因此您永远无法获得良好的性能。

DECLARE @t table (
   a char(10)
);

INSERT INTO @t (a)
  VALUES ('AbC')
       , ('ABCDEFGHIJ')
       , ('aBCdEFghij')
       , ('AbcdefhhiJ')
       , ('ABcdEFGhij')
;

--SELECT a
--     , a COLLATE SQL_Latin1_General_CP1_CS_AS As case_sensitive_collation
--     , Replace(a COLLATE SQL_Latin1_General_CP1_CS_AS, 'A', '#') As case_sensitive_replace
--FROM   @t
--;

; WITH characters_to_replace AS (
  SELECT number
       , Char(number) As c
       , Row_Number() OVER (ORDER BY number) As sequence
  FROM   dbo.numbers
  WHERE  number BETWEEN 1 AND 255 -- basic characters
  AND    number NOT BETWEEN 65 AND 90 -- Exclude capital A-Z
)
, replacements AS (
SELECT a As original_value
     , Cast(a COLLATE SQL_Latin1_General_CP1_CS_AS As nvarchar(max)) As new_value
     , Cast(0 As bigint) As sequence
FROM   @t

  UNION ALL

    SELECT replacements.original_value
         , Cast(Replace(replacements.new_value, characters_to_replace.c, '') As nvarchar(max))
         , characters_to_replace.sequence
    FROM   replacements
     INNER
      JOIN characters_to_replace
        ON characters_to_replace.sequence = replacements.sequence + 1
)
SELECT original_value
     , new_value
FROM   replacements
WHERE  sequence = (SELECT Max(sequence) FROM characters_to_replace)
OPTION (MaxRecursion 255)
;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接