How can I switch case for each letter in a string with SQL?

前端 未结 4 501
旧时难觅i
旧时难觅i 2021-01-29 11:27

I need to convert this into this using PostgreSQL

dxItw9a4 --> DXiTW9A4

Is there any function or way that is already set?

相关标签:
4条回答
  • 2021-01-29 11:47

    If you're only dealing with the characters A-Z, you can use the translate function in postgres to convert cases.

    select TRANSLATE(
        'dxItw9a4', -- original text
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', -characters to change
        'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' -- replacement characters.
    )
    

    You can simplify it slightly be using the upper/lower functions.

    select TRANSLATE(
        'dxItw9a4',  -- original text
        upper('dxItw9a4')||lower('dxItw9a4'), --characters to search for
        lower('dxItw9a4')||upper('dxItw9a4') -- replacement characters
    );
    
    
    0 讨论(0)
  • 2021-01-29 11:48

    It sounds like the OP is looking for a SQL version of the swapcase() function found in many client-side languages. A few thoughts:

    1. Use swapcase() on the client side. I'd do that.
    2. Figure out a clever regex? I'm not that clever.
    3. Roll something by hand.

    I figured I'd give #3 a try, and wrote some code. The kindest thing I can say about this function is that it works...but I doubt it's much good. I'm trying to beef up my PL/pgSQL skills, so any comments on improving the code welcomed. It's so much easier to write a lot of things in most other languages...but there are plenty of cases where pushing the logic onto the server is beneficial, I figure it's worth putting in some effort to get comfortable in PL/pgSQL. But, again, I'd use swapcase(), or a hand-rolled equivalent, on the client side, I'd expect.

    CREATE OR REPLACE FUNCTION swapcase(in_text text) RETURNS text as
    $BODY$
    DECLARE
        out_text text;
        test_char text;
        ascii_code smallint;
        characters_arr_text  text[];
    begin
    
       out_text  :='';
       test_char := '';
       select into characters_arr_text regexp_split_to_array(in_text,'');
    
        FOREACH test_char IN array characters_arr_text LOOP
    
            ascii_code := ascii(test_char);
    
            IF (ascii_code BETWEEN 65 and 90) THEN 
                out_text := out_text || LOWER(test_char);
    
            ELSIF (ascii_code BETWEEN 97 and 122) THEN 
                out_text := out_text || UPPER(test_char);
    
             ELSE
              out_text := out_text || test_char;
            END IF;
    
        END LOOP;
    
        RETURN out_text;
    
    END
    $BODY$
    LANGUAGE 'plpgsql';
    

    Here's a call:

    select swapcase('dxItw9a4'); --  DXiTW9A4
    

    And a longer call to show that it works:

    select 'dxItw9a4' as input,
            swapcase('dxItw9a4') as output,
            'DXiTW9A4' as expected_output,
            swapcase('dxItw9a4') = 'DXiTW9A4' as pass;
    

    Better

    Here's a swapcase() function that uses GMB's code.

    CREATE OR REPLACE FUNCTION swapcase(in_text text) RETURNS text as
    $BODY$
    
        select string_agg(
                    case when character ~ '[a-z]' then 
                        upper(character) 
                    else 
                        lower(character)
                     end, '') as result_text
    
        from (select * 
                from regexp_split_to_table(in_text, '') as character) as subquery
    
    $BODY$
    LANGUAGE 'sql';
    
    0 讨论(0)
  • 2021-01-29 11:51

    You can use the following methods supported by PostreSQL:

    UPPER(string_expression)
    

    Example:

    SELECT
       CONCAT (
          UPPER (first_name),
          UPPER (last_name)
       ) as full_name
    FROM
       staff;
    

    Reference: http://www.postgresqltutorial.com/postgresql-letter-case-functions/

    0 讨论(0)
  • 2021-01-29 12:00

    Here is a solution that works by splitting the string into a resultset of charaters using regexp_split_to_table(), then converts them to the opposite case and joins them again using aggregate function string_agg():

    select 
        string_agg(case when c ~ '[a-z]' then upper(c) else lower(c) end, '') res
    from (
        select * from regexp_split_to_table('dxItw9a4', '') as chars(c)
    ) x
    

    Demo on DB Fiddle:

    | res      |
    | :------- |
    | DXiTW9A4 |
    
    0 讨论(0)
提交回复
热议问题