web-dev-qa-db-fra.com

Convertir la chaîne en nombre, interprétant la chaîne nulle ou vide comme 0

J'ai une table Postgres avec une colonne de chaîne contenant des valeurs numériques. J'ai besoin de convertir ces chaînes en nombres pour les mathématiques, mais j'ai besoin des valeurs NULL ainsi que des chaînes vides à interpréter comme 0.

Je peux convertir des chaînes vides en valeurs nulles :

# select nullif('','');
 nullif 
--------

(1 row)

Et je peux convertir des valeurs nulles en 0 :

# select coalesce(NULL,0);
 coalesce 
----------
        0
(1 row)

Et je peux convertir les chaînes en nombres :

# select cast('3' as float);
 float8 
--------
      3
(1 row)

Mais lorsque j'essaie de combiner ces techniques, j'obtiens des erreurs:

# select cast( nullif( coalesce('',0), '') as float);
ERROR:  invalid input syntax for integer: ""
LINE 1: select cast( nullif( coalesce('',0), '') as float);

# select coalesce(nullif('3',''),4) as hi;
ERROR:  COALESCE types text and integer cannot be matched
LINE 1: select coalesce(nullif('3',''),4) as hi;

Qu'est-ce que je fais mal?

29
Phrogz

Les types de valeurs doivent être cohérents; la fusion de la chaîne vide à un 0 signifie que vous ne pouvez pas la comparer à null dans le nullif. Donc, l'un de ces travaux:

# create table tests (orig varchar);
CREATE TABLE

# insert into tests (orig) values ('1'), (''), (NULL), ('0');
INSERT 0 4


# select orig, cast(coalesce(nullif(orig,''),'0') as float) as result from tests;
 orig | result 
------+--------
    1 |      1
      |      0
      |      0
    0 |      0
(4 rows)


# select orig, coalesce(cast(nullif(orig,'') as float),0) as result from tests;
 orig | result 
------+--------
 1    |      1
      |      0
      |      0
 0    |      0
(4 rows)
34
Phrogz

Vous pouvez également utiliser

cast(
    case
        when coalesce(orig, '') = '' then '0'
        else orig
    end
    as float
)

Vous pouvez également déballer cela un peu puisque vous commencez de toute façon assez verbeux:

cast(
    case
        when orig is null then '0'
        when orig = '' then '0'
        else orig
    end
    as float
)

ou vous pouvez mettre le plâtre à l'intérieur du CAS:

case
    when coalesce(orig, '') = '' then 0.0
    else cast(orig as float)
end

Un CASE facilite un peu la prise en compte d'autres conditions spéciales, cela semble également être une expression plus claire de la logique IMO. OTOH, goût personnel et tout ça.

8
mu is too short

En fait, vous pouvez convertir NULL en int, vous ne pouvez simplement pas convertir une chaîne vide en int. En supposant que vous vouliez NULL dans la nouvelle colonne si data1 contient une chaîne vide ou NULL, vous pouvez faire quelque chose comme ceci:

UPDATE table SET data2 = cast(nullif(data1, '') AS int);

ou

UPDATE table SET data2 = nullif(data1, '')::int;

Référence

5
florentpousserot