Дата передачи хранимой процедуре в ошибке Oracle SQL: ORA-01858 - PullRequest
0 голосов
/ 29 мая 2020

Я знаю, что на этот вопрос уже был дан ответ, и я безуспешно опробовал данное в них решение.

У меня есть хранимая процедура, как показано ниже (я удалил несущественные части):

CREATE OR REPLACE PROCEDURE get_days(dt date)
IS
  given_date DATE := TO_DATE('dt', 'DD-MON-YYYY');
BEGIN
  get_day := RTRIM(TO_CHAR(dt1, 'DAY'));
  DBMS_OUTPUT.PUT_LINE ('The day of the given date is '||get_day||);
  DBMS_OUTPUT.PUT_LINE ('Execution  done successfully.');
END get_days;

У меня возникли проблемы с передачей даты в процедуру get_days. Я пробовал следующими способами:

BEGIN
  --Below I have listed all ways I have tried 
  get_days('12/12/12');
  get_days('12-12-12');
  get_days(date '2012-12-12');  
  get_days(TO_DATE( '01/01/2018', 'MM/DD/YYYY' ));
END;

Я не знаю, что не так, но получаю эту ошибку - ORA-01858: a non-numeric character was found where a numeric was expected. Я искал похожие ошибки в Интернете, но ничего не помогло. Я использую Oracle Database 11g Express edition . Вероятно, в моем коде есть небольшая ошибка, но я не понимаю, что это такое.

Любая помощь приветствуется!

1 Ответ

1 голос
/ 29 мая 2020

Непосредственной причиной ошибки является наличие

  given_date DATE := TO_DATE('dt', 'DD-MON-YYYY');

вместо

  given_date DATE := TO_DATE(dt, 'DD-MON-YYYY');

В вашей версии вы пытаетесь преобразовать строковый литерал 'dt' в дату ; этот литерал не имеет отношения к вашему аргументу dt.

Однако это все равно неверно, поскольку dt уже объявлен как тип данных даты. Если вы это сделаете, то вы действительно делаете:

  given_date DATE := TO_DATE(TO_CHAR(dt), 'DD-MON-YYYY');

, который будет использовать ваш текущий сеанс NLS_DATE_FORMAT для преобразования даты в строку; если это тоже не «ДД-МЕС-ГГГГ» (или что-то достаточно близкое, чтобы Oracle обманул ), вы все равно получите ошибку или, что еще хуже, неправильное преобразование и недопустимые результаты, которые вы может не заметить.

Так что удалите это избыточное и опасное преобразование:

CREATE OR REPLACE PROCEDURE get_days(dt date)
IS
BEGIN
  DBMS_OUTPUT.PUT_LINE ('The day of the given date is ' || TO_CHAR(dt, 'FMDAY') || '.');
  DBMS_OUTPUT.PUT_LINE ('Execution  done successfully.');
END get_days;
/

Конечно, вы можете присвоить название дня строковой переменной, если хотите. Я использовал модификатор формата FM , чтобы не допустить, чтобы он дополнял название дня справа, поэтому вам не нужно обрезать его - точка просто нужна, чтобы продемонстрировать, что работает. Если вы хотите, чтобы название дня было в смешанном регистре, вы можете использовать 'FMDay' вместо 'FMDAY'.

Вы всегда должны передавать дату, а не строку:

set serveroutput on;

BEGIN
  get_days(date '2012-12-12');  
  get_days(TO_DATE( '01/01/2018', 'MM/DD/YYYY' ));
END;
/

The day of the given date is WEDNESDAY.
Execution  done successfully.
The day of the given date is MONDAY.
Execution  done successfully.


PL/SQL procedure successfully completed.

dt можно передавать в любом формате. Я просто конвертирую его в формат ДД-ММ-ГГГГ и сохраняю в given_date

Дата не имеет формата; у него есть внутреннее представление, о котором вам очень редко нужно знать или о котором нужно заботиться. Когда вы запрашиваете значение даты без явного преобразования его в строку, ваш клиент преобразует его в удобочитаемую форму, обычно используя NLS_DATE_FORMAT, чтобы решить, в каком формате его отображать. Итак, dt не имеет формата, и даже если вызывающий выполняет вызов со строкой (как в ваших первых двух примерах), они будут неявно преобразованы в дату - если это возможно - перед вызовом; процедура никогда не увидит эти строки, она увидит только преобразованное значение даты.

...