2017-07-17 2 views
1

J'utilise Firebird 2.5. Quand je lanceSQL avec CASE imbriqué et les chaînes jointes donne des espaces de fin

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 sur le terrain est 'NUME ' (il y a 4 espaces après NUME) et BILANCA1 est 'NUME'. Le nombre d'espaces ajoutés est égal à la longueur de la chaîne la plus longue dans CASE. La seule différence se trouve dans la chaîne de jonction en BILANCA1:

ELSE 'A'||'B' END 

DDL est

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

Tableau Ses 2:

Résultat est

  • 'NUME ' (il y a 4 espaces après NUME), 'NUME'

  • 'AB', 'AB'

Question: Est-ce attendu et pourquoi?

Répondre

2

Les littéraux de chaîne dans Firebird sont de type CHAR, le type de données d'une expression de cas aura la plus grande longueur de toutes les branches. Donc, avec

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

Le type de données sera CHAR(8). Une valeur CHAR sera toujours correctement remplie avec les espaces à la longueur déclarée.

Toutefois, lorsque l'une des branches d'une expression de cas est VARCHAR, toutes les branches sont forcées à VARCHAR. Et concaténation Firebird produira toujours un VARCHAR, même si les deux opérandes sont CHAR

Cela signifie que dans le cas de BILANCA1:

CASE BILANCA 
WHEN 1 THEN 
    CASE BILANCA WHEN 0 THEN 'SMALLINT' WHEN 1 THEN 'NUME' END 
ELSE 'A'||'B' END 

que 'A'||'B' est un VARCHAR(2), ce qui provoque toute l'affaire à sous la contrainte à VARCHAR, ce qui provoque alors 'SMALLINT' pour devenir un VARCHAR(8) et 'NUME' un VARCHAR(4), ce qui rend l'expression entière devient VARCHAR(8).

Notez que ce type de coercition est poussé vers le bas, de sorte que le littéral sera varchar dès le début et ne sera pas masqué * par une évaluation intermédiaire de l'instruction case la plus interne.

Ce n'est pas le cas pour BILANCA2, étant donné que toutes les branches (imbriquées) sont des littéraux, ce sera CHAR(8).

Si vous voulez à la fois pour le même comportement que vous pouvez faire:

  1. Cast l'expression entière du type souhaité (cela fonctionnerait aussi bien pour bilanca1 et bilanca2)
  2. partie Cast de l'expression (par exemple un des littéraux ou le cas imbriqué) à varchar; cela fonctionne uniquement pour forcer bilanca2 à varchar
  3. Transmettez la concaténation de chaîne à char; cela fonctionne uniquement pour forcer bilanca1 à char
  4. Concaténer une chaîne vide à l'un des littéraux; cela ne fonctionne que pour forcer bilanca2 à un varchar
  5. Utilisation trim sur l'expression entière (cela aussi contraint à varchar)

*) Ceci contraste avec par exemple cast(cast('nume' as char(8)) as varchar(8)) qui produira 'nume ' et non pas seulement 'nume' comme dans ce cas le résultat intermédiaire est préservé, et les espaces existants ne sont pas jetés dans un varchar.