web-dev-qa-db-fra.com

Oracle - Pourquoi le premier zéro d'un nombre disparaît-il lors de sa conversion en TO_CHAR

Dans Oracle, lors de la conversion d'un nombre avec un zéro non significatif en caractère, pourquoi le nombre non significatif disparaît-il? Cette logique est-elle spécifique à Oracle ou spécifique à SQL?

Exemple:

SELECT TO_CHAR(0.56) FROM DUAL;
/* Result = .56 */
34
contactmatt

C'est la mise en forme par défaut qu'Oracle fournit. Si vous voulez des zéros non significatifs en sortie, vous devrez fournir explicitement le format. Utilisation:

SELECT TO_CHAR(0.56,'0.99') FROM DUAL;

ou même:

SELECT TO_CHAR(.56,'0.99') FROM DUAL;

Il en va de même pour les zéros de fin:

SQL> SELECT TO_CHAR(.56,'0.990') val FROM DUAL;

VAL
------
 0.560

La forme générale de la fonction de conversion TO_CHAR est:

TO_CHAR (nombre, format )

30
DCookie

Je cherchais un moyen de formater les nombres sans interligne ni arrière espaces , points, zéros (sauf un zéro initial pour les nombres inférieurs à 1 qui devraient être présents).

Cela est frustrant de constater que la mise en forme la plus courante ne peut pas être facilement réalisée dans Oracle.

Même Tom Kyte a seulement suggéré une solution de contournement longue et compliquée comme ceci:

case when trunc(x)=x
    then to_char(x, 'FM999999999999999999')
    else to_char(x, 'FM999999999999999.99')
end x

Mais j'ai pu trouver une solution plus courte qui ne mentionne la valeur qu'une seule fois:

rtrim(to_char(x, 'FM999999999999990.99'), '.')

Ceci fonctionne comme prév pour toutes les valeurs possibles:

select 
    to_char(num, 'FM99.99') wrong_leading_period,
    to_char(num, 'FM90.99') wrong_trailing_period,
    rtrim(to_char(num, 'FM90.99'), '.') correct
from (
  select num from (select 0.25 c1, 0.1 c2, 1.2 c3, 13 c4, -70 c5 from dual)
  unpivot (num for dummy in (c1, c2, c3, c4, c5))
) sampledata;

    | WRONG_LEADING_PERIOD | WRONG_TRAILING_PERIOD | CORRECT |
    |----------------------|-----------------------|---------|
    |                  .25 |                  0.25 |    0.25 |
    |                   .1 |                   0.1 |     0.1 |
    |                  1.2 |                   1.2 |     1.2 |
    |                  13. |                   13. |      13 |
    |                 -70. |                  -70. |     -70 |

Toujours à la recherche d'une solution encore plus courte.

Il existe une approche raccourcie avec une fonction d'assistance personnalisée:

create or replace function str(num in number) return varchar2
as
begin
    return rtrim(to_char(num, 'FM999999999999990.99'), '.');
end;

Mais les fonctions pl/sql personnalisées ont un surdébit performant qui ne convient pas aux requêtes lourdes.

28
Vadzim

On dirait que la seule façon d'obtenir des décimales sous une jolie forme (pour moi) nécessite du code ridicule.

La seule solution que j'ai obtenue jusqu'à présent:

CASE WHEN xy>0 and xy<1 then '0' || to_char(xy) else to_char(xy)

xy est une décimale.

xy             query result
0.8            0.8  --not sth like .80
10             10  --not sth like 10.00

veuillez répondre à cette question s'il existe une option de format réel pour cela.

7
mkb

Cela ne fonctionne que pour les nombres inférieurs à 1.

select to_char(12.34, '0D99') from dual;
-- Result: #####

Ça ne marchera pas.

Vous pouvez faire quelque chose comme ça, mais cela se traduit par des espaces blancs de premier plan:

select to_char(12.34, '999990D99') from dual;
-- Result: '     12,34'

En fin de compte, vous pourriez ajouter un TRIM pour vous débarrasser à nouveau des espaces blancs, mais je ne considérerais pas non plus une solution appropriée ...

select trim(to_char(12.34, '999990D99')) from dual;
-- Result: 12,34

Encore une fois, cela ne fonctionnera que pour les numéros à 6 chiffres max.

Edit: je voulais ajouter ceci comme un commentaire sur la suggestion de DCookie mais je ne peux pas.

4
rawberto

Essayez ceci pour éviter les limitations de to_char:

SELECT 
regexp_replace(regexp_replace(n,'^-\'||s,'-0'||s),'^\'||s,'0'||s)
FROM (SELECT -0.89 n,RTrim(1/2,5) s FROM dual);
1
user6404490

Devrait fonctionner dans tous les cas:

SELECT regexp_replace(0.1234, '^(-?)([.,])', '\10\2') FROM dual
0
Joël