Подтвердить что ты не робот

Oracle. Почему начальный ноль числа исчезает при преобразовании TO_CHAR

В Oracle при преобразовании числа с начальным нулем в символ почему исчезает лидирующее число? Является ли эта логика Oracle специфичной или специфичной для SQL?

Пример:

SELECT TO_CHAR(0.56) FROM DUAL;
/* Result = .56 */
4b9b3361

Ответ 1

Это форматирование по умолчанию, предоставляемое Oracle. Если вы хотите, чтобы на выходе были начальные нули, вам нужно явно указать формат. Использование:

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

или даже:

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

То же самое верно для конечных нулей:

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

VAL
------
 0.560

Общая форма функции преобразования TO_CHAR:

TO_CHAR(число, формат)

Ответ 2

Я искал способ форматирования чисел без начальных или конечных пробелов, точек, нулей (за исключением одного начального нуля для чисел меньше 1, которые должны присутствовать).

Это огорчает, что такое самое обычное форматирование не может быть легко достигнуто в Oracle.

Даже Том Кайт предложил только длинный сложный обходной путь, например:

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

Но мне удалось найти более короткое решение, которое упоминает значение только один раз:

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

Это работает как положено для всех возможных значений:

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 |

Все еще ищу более короткое решение.

Существует сокращенный подход с пользовательской вспомогательной функцией:

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

Но пользовательские функции pl/sql имеют значительные издержки производительности, что не подходит для сложных запросов.

Ответ 3

Кажется, что единственный способ получить десятичную форму в симпатичной (для меня) форме требует какого-то смешного кода.

Единственное решение, которое я получил до сих пор:

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

xy является decimial.

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

ответьте на этот вопрос, если для этого есть реальная форма.

Ответ 4

Это работает только для чисел меньше 1.

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

Это не сработает.

Вы можете сделать что-то подобное, но это приводит к ведущим пробелам:

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

В конечном итоге вы можете добавить TRIM, чтобы избавиться от лишних пробелов, но я не стал бы считать, что это правильное решение...

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

Опять же, это будет работать только для чисел с макс. 6 цифр.

Изменить: я хотел добавить это как комментарий к предложению DCookie, но я не могу.

Ответ 5

Попробуйте это, чтобы избежать ограничений 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);

Ответ 6

Должно работать во всех случаях:

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