嵌套CASE和连接字符串的SQL提供尾随空格

时间:2017-07-17 09:18:47

标签: sql firebird firebird2.5

我正在使用Firebird 2.5。我跑的时候

SELECT 
CASE BILANCA 
  WHEN 1 THEN
    CASE BILANCA WHEN 0 THEN 'SMALLINT' WHEN 1 THEN 'NUME' END
  ELSE 'A'||'B' END
  AS BILANCA1,
  CASE BILANCA 
  WHEN 1 THEN
    CASE BILANCA WHEN 0 THEN 'SMALLINT' WHEN 1 THEN 'NUME' END
  ELSE 'AB' END
  AS BILANCA2
FROM GS01BILANCA

字段BILANCA2为'NUME '(NUME后有4个空格),BILANCA1为'NUME'。添加的空格数等于CASE中最长字符串的长度。 唯一的区别是在BILANCA1中加入字符串:

ELSE 'A'||'B' END

DDL

CREATE TABLE GS01BILANCA
(BILANCA INTEGER DEFAULT  0 NOT NULL,
CONSTRAINT PK_GS01BILANCA PRIMARY KEY (BILANCA));

表有2条记录:

  • 1
  • 2

结果是

  • 'NUME '(NUME后有4个空格),'NUME'

  • 'AB''AB'

问题:这是预期的吗?为什么?

1 个答案:

答案 0 :(得分:2)

Firebird中的字符串文字属于CHAR类型,案例表达式的数据类型将具有所有分支的最长长度。所以用

CASE BILANCA WHEN 0 THEN 'SMALLINT' WHEN 1 THEN 'NUME' END

数据类型为CHAR(8)CHAR值将始终右对齐,空格为声明的长度。

但是,当案例表达式的一个分支是VARCHAR时,则所有分支都被强制转换为VARCHAR。 Firebird中的串联将始终生成VARCHAR,即使两个操作数都是CHAR

这意味着在BILANCA1

的情况下
CASE BILANCA 
WHEN 1 THEN
    CASE BILANCA WHEN 0 THEN 'SMALLINT' WHEN 1 THEN 'NUME' END
ELSE 'A'||'B' END

'A'||'B'VARCHAR(2),这会导致整个案例被强制转移到VARCHAR,从而导致'SMALLINT'成为VARCHAR(8)和{ {1}} 'NUME',这使得整个表达式变为VARCHAR(4)

请注意,此类型强制被推下,因此文字从一开始就是VARCHAR(8),并且不会通过对最内层case语句的中间评估来填充*。

varchar不是这种情况,因为所有(嵌套)分支都是文字,因此它将是BILANCA2

如果您希望两者的行为相同,则可以执行以下操作:

  1. 将整个表达式投射到所需的类型(这对CHAR(8)bilanca1都适用
  2. 将表达式的一部分(例如,一个文字或嵌套的大小写)转换为bilanca2;这仅适用于强制varchar bilanca2
  3. 将字符串连接转换为varchar;这仅适用于强制char bilanca1
  4. 将空字符串连接到其中一个文字;这仅适用于强制char bilanca2
  5. 在整个表达式上使用varchar(这也强制为trim
  6. *)这与例如varchar形成对比,后者将产生cast(cast('nume' as char(8)) as varchar(8))而不仅仅是'nume ',因为在这种情况下保留了中间结果,并且不会丢弃现有空格'nume'