【问题标题】:Spaces when concatenating multiple columns and one column is null - Oracle连接多列且一列为空时的空格 - Oracle
【发布时间】:2012-08-11 00:18:32
【问题描述】:

我需要将几列连接成一列,每个值之间有空格。问题是当一个值为空时,我最终会在两个值之间出现一个双空格。

例子

SELECT (FIRST_NAME || ' ' || MIDDLE_NAME || ' ' || LAST_NAME
  FROM TABLE_A;

如果中间名恰好为 NULL,那么我的名字和姓氏之间会出现两个空格。有什么办法可以解决这个问题,当有空值时只有一个空格?

【问题讨论】:

    标签: oracle null concatenation space


    【解决方案1】:
    SELECT TRIM(TRIM(FIRST_NAME || ' ' || MIDDLE_NAME) || ' ' || LAST_NAME)   
    FROM TABLE_A; 
    

    【讨论】:

    • 这个是最正确的,因为公认的方法不认为前两个参数可能是 NULL。
    【解决方案2】:

    来自 Oracle 的文档:

    CONCAT_WS(分隔符,str1,str2,...)

    CONCAT_WS() 代表 Concatenate With Separator 并且是一个特殊的 CONCAT() 的形式。第一个参数是其余部分的分隔符 论据。分隔符被添加到字符串之间 串联。分隔符可以是字符串,其余部分也可以 论据。如果分隔符为 NULL,则结果为 NULL。

    还有非常重要的评论:

    CONCAT_WS() 不会跳过空字符串。但是,它确实跳过了任何 分隔符参数后的 NULL 值。

    所以在你的情况下应该是:

    CONCAT_WS(',', FIRST_NAME, MIDDLE_NAME, LAST_NAME);
    

    【讨论】:

    • 如果我错了,请纠正我,但 CONCAT_WS() 在 MySQL 中可用,而不是 Oracle RDBMS。
    【解决方案3】:
    with indata as
    (
    select 'John' as first_name, 'W' as middle_name, 'Smith ' as last_name from dual
    union
    select null as first_name, null as middle_name, 'Adams' as last_name from dual
    union
    select 'Tom' as first_name, null as middle_name, 'Jefferson' as last_name from dual
    )
    select
    regexp_replace(trim(indata.first_name || ' ' || indata.middle_name || ' ' || indata.last_name), '\s{2,}', ' ')
    from indata;
    

    【讨论】:

    • 哈!即将发布 regexp_replace 方法!
    【解决方案4】:

    这就是我通常在 Oracle 中连接多个字段并删除空格的方式:

    TRIM(REGEXP_REPLACE(HOUSE_NO || ' ' || PREFIX || ' ' || STREET_NAME || ' ' || STREET_TYPE || ' ' || SUFFIX, ' +', ' '))

    1. 连接所有必要的字段,每个字段之间有一个空格。空字符串和 NULL 值将导致两个或多个空格;
    2. 使用正则表达式将出现的多个空格 ['+'] 更改为单个空格 [''];
    3. 最后,修剪结果字符串开头和/或结尾的所有空格。

    【讨论】:

    • 我使用 regexp_replace 来解决这个问题,但它是作为 REGEX_REPLACE( , '\s{2,}', ' ') 来连续查找 2 个或多个空格。
    【解决方案5】:

    您可以使用RPAD() 来添加空格字符:

    SELECT RPAD(first_name, LENGTH(first_name)+1, ' ')||RPAD(middle_name, LENGTH(middle_name)+1, ' ')||last_name
    FROM TABLE_A;
    

    RPAD 的任何参数为 NULL 时,结果将为 NULL,并且在 Oracle 中将 NULL 附加到字符串会返回原始字符串。

    【讨论】:

      【解决方案6】:

      另一种选择是使用解码:

      SELECT decode(FIRST_NAME,'','',FIRST_NAME ||' ') ||
             decode(MIDDLE_NAME,'','',MIDDLE_NAME ||' ') || LAST_NAME
      FROM TABLE_A;
      

      【讨论】:

      • 我最终使用了您之前发布的 NVL() 方法。我确实发现表格中有一些值是空白的(或者我认为)但实际上有一个空格,所以这些行让我很困惑
      • ...我收回了。我必须像上面那样合并解码。感谢您的帮助
      • 由于 '' 在 Oracle 中为 null,因此此处的 nvl 调用不会增加任何价值。 “如果 FIRST_NAME 为 null,则返回 null,否则返回 FIRST_NAME”与“返回 FIRST_NAME”相同。
      【解决方案7】:

      另一种选择:

      SELECT first_name
             || DECODE(middle_name
                ,      NULL, NULL
                ,      ' ' || middle_name)
             || DECODE(last_name
                ,      NULL, NULL
                ,      ' ' || last_name) full_name
      FROM   table_a
      ;
      

      【讨论】:

      • 如果 middle_name 或 last_name 为空字符串(即 '') - 它不能正常工作...
      • 在 Oracle 中它会; Oracle 不区分空字符串和NULL
      【解决方案8】:

      或者您可以简单地使用 REPLACE 函数:

      with indata as 
        (select 'John' as first_name, 'W' as middle_name, 'Smith ' as last_name from dual 
         union 
         select null as first_name, null as middle_name, 'Adams' as last_name from dual 
          union 
          select 'Tom' as first_name, null as middle_name, 'Jefferson' as last_name from dual) 
      SELECT REPLACE(TRIM(indata.first_name || ' ' || indata.middle_name || ' ' || indata.last_name), '  ', ' ')
        FROM indata
      

      (感谢@tbone 提供的示例数据:-)

      【讨论】:

        【解决方案9】:

        我通过示例解决了这个问题。希望这可以帮助。只需转到 SQL 服务器,选择新查询和 CP 以下查询:

        DECLARE @NULL_SAMLES TABLE
               (
               NS_ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED NOT NULL
              ,COL_01 VARCHAR(10) NULL
              ,COL_02 VARCHAR(10) NULL
              ,COL_03 VARCHAR(10) NULL
              ,COL_04 VARCHAR(10) NULL
           )
        
           INSERT INTO @NULL_SAMLES(COL_01,COL_02,COL_03,COL_04)
           VALUES
            ('A','B','C','D')
           ,(' ' ,'B','C','D')
           ,(' ',NULL,'C','D')
           ,('A','B',NULL,'D')
           ,('A','B','C',NULL)
           ,(NULL,'B',NULL,'D')
           ,(NULL,'B','C',NULL)
           ,('A',NULL,'C',NULL)
           ,('A',NULL,NULL,'D')
           ,('A',NULL,NULL,NULL)
           ,(NULL,'B',NULL,NULL)
           ,(NULL,NULL,'C',NULL)
           ,(NULL,NULL,NULL,'D')
        
        
           SELECT
                NS.COL_01
               ,NS.COL_02
               ,NS.COL_03
               ,NS.COL_04,
              Stuff(  
                Coalesce(', ' + nullif(NS.COL_01, ''), '') 
              + Coalesce(', ' + nullif(NS.COL_02, ''), '') 
              + Coalesce(', ' + nullif(NS.COL_03, ''), '') 
              +Coalesce(', ' + nullif(NS.COL_04, ''), '')
              , 1, 1, '') AS CONC_COLS
           FROM @NULL_SAMLES NS
        

        【讨论】:

          【解决方案10】:

          不要低估 CASE 语句的简单功能,它可以连接起来。这是一个可以按原样运行的独立示例:

          SELECT
          CASE WHEN x.FIRST_NAME IS NULL THEN x.FIRST_NAME ELSE x.FIRST_NAME || ' ' END || 
          CASE WHEN x.MIDDLE_NAME IS NULL THEN x.MIDDLE_NAME ELSE x.MIDDLE_NAME  || ' ' END || 
          x.LAST_NAME
          FROM (SELECT 'John' AS FIRST_NAME, NULL AS MIDDLE_NAME, 'Doe' AS LAST_NAME FROM DUAL) x;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-11-08
            • 2020-07-07
            • 1970-01-01
            • 1970-01-01
            • 2020-02-09
            • 2016-01-20
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多