Запрос работает вне хранимой процедуры, но внутри процедуры он выдает ошибку - PullRequest
0 голосов
/ 04 июля 2018

Запрос на выборку отлично работает вне процедуры пакета, но внутри процедуры он выдает «ORA-01858: не числовой символ был найден там, где ожидалось числовое значение».

Вот мой запрос:

DECLARE
      v_general_number VARCHAR(11);
BEGIN
      SELECT 'Q' || TO_CHAR(TO_DATE(SYSDATE, 'MM/DD/YYYY'), 'Q') || '/'  ||   LPAD(TO_CHAR(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL), '3', '0')  || '/' || TO_CHAR(EXTRACT(YEAR FROM TO_DATE(SYSDATE, 'MM/DD/YYYY'))) INTO v_general_number FROM DUAL;
      DBMS_OUTPUT.PUT_LINE(v_general_number);
END;

И это работает довольно хорошо.

Но внутри хранимой процедуры выдает ошибку выше.

Вот моя процедура:

   PROCEDURE save_request(p_name IN requests.suggested_name%TYPE,
                          p_urgency_type IN requests.urgency_type_id%TYPE) 
   AS

      v_general_number VARCHAR(11);

   BEGIN

   SELECT 'Q' || TO_CHAR(TO_DATE(SYSDATE, 'MM/DD/YYYY'), 'Q') || '/'  ||  LPAD(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL, 3, '0')  ||  '/' ||  TO_CHAR(EXTRACT(YEAR FROM TO_DATE(SYSDATE, 'MM/DD/YYYY')))  INTO v_general_number FROM DUAL;

   INSERT INTO requests (suggested_name,
                          urgency_type_id,
                          general_number 
      ) VALUES (
          p_name ,
          p_urgency_type ,
          v_general_number );



    END save_request;

Я не вижу, в чем проблема. Любые предложения будут оценены.

ОБНОВЛЕНИЕ:

Я решил проблему после изменения этого:

SELECT 'Q' || TO_CHAR(TO_DATE(SYSDATE, 'MM/DD/YYYY'), 'Q') || '/'  ||  LPAD(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL, 3, '0')  ||  '/' ||  TO_CHAR(EXTRACT(YEAR FROM TO_DATE(SYSDATE, 'MM/DD/YYYY')))   INTO v_general_number FROM DUAL;

На это:

SELECT 'Q' || TO_CHAR(SYSDATE, 'Q') || '/'  ||  LPAD(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL, 3, '0')  ||  '/' ||  TO_CHAR(EXTRACT(YEAR FROM SYSDATE))  INTO v_general_number FROM DUAL;

И это сработало.

Но я до сих пор не понимаю, почему тот же запрос работает вне процедуры, но выдает ошибку внутри процедуры.

1 Ответ

0 голосов
/ 04 июля 2018

SYSDATE уже дата, поэтому

TO_DATE(SYSDATE, 'MM/DD/YYYY')

на самом деле не имеет смысла. Вы делаете неявное преобразование в строку, а затем явное преобразование в дату, то есть фактически:

TO_DATE(TO_CHAR(SYSDATE, <NLS_DATE_FORMAT>), 'MM/DD/YYYY')

Работает ли это, зависит от настройки NLS_DATE_FORMAT вашей сессии:

alter session set nls_date_format = 'MM/DD/YYYY';
select TO_DATE(SYSDATE, 'MM/DD/YYYY') from dual;

TO_DATE(SY
----------
07/04/2018

select TO_CHAR(TO_DATE(SYSDATE, 'MM/DD/YYYY'), 'YYYY-MM-DD') from dual;

TO_CHAR(TO
----------
2018-07-04

alter session set nls_date_format = 'DD/MM/YYYY';
select TO_DATE(SYSDATE, 'MM/DD/YYYY') from dual;

TO_DATE(SY
----------
07/04/2018

select TO_CHAR(TO_DATE(SYSDATE, 'MM/DD/YYYY'), 'YYYY-MM-DD') from dual;

TO_CHAR(TO
----------
2018-04-07

alter session set nls_date_format = 'DD-MON-YYYY';
select TO_DATE(SYSDATE, 'MM/DD/YYYY') from dual;

ORA-01858: a non-numeric character was found where a numeric was expected

alter session set nls_date_format = 'YYYY-MM-DD';
select TO_DATE(SYSDATE, 'MM/DD/YYYY') from dual;

ORA-01843: not a valid month

Обратите внимание, что первые два «работают», но на самом деле дают разные даты. (Позже в этом месяце, после 12-го, второй тоже не удастся с ошибкой неправильного месяца.)

Сессия, из которой вы запускаете анонимный блок, и сессия, из которой вы выполняете процедуру, просто имеют разные настройки NLS. Вот почему вы не должны полагаться на неявное преобразование или настройки NLS ...

В любом случае удалите ненужные преобразования:

SELECT 'Q' || TO_CHAR(SYSDATE, 'Q')
  || '/' || LPAD(TO_CHAR(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL), '3', '0') 
  || '/' || TO_CHAR(EXTRACT(YEAR FROM SYSDATE))
INTO v_general_number
FROM DUAL;

или сделать то же самое с заданием вместо выбора из двойного:

v_general_number := 'Q' || TO_CHAR(SYSDATE, 'Q')
  || '/' || LPAD(TO_CHAR(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL), '3', '0')
  || '/' || TO_CHAR(EXTRACT(YEAR FROM SYSDATE));

или даже просто как альтернатива:

v_general_number := TO_CHAR(SYSDATE, '"Q"Q"/"')
  || TO_CHAR(SEQ_EDP_GENERAL_NUM_ID.NEXTVAL, 'FM000')
  || TO_CHAR(SYSDATE, '"/"YYYY');

, который использует символьные литералы в моделях формата даты для замены конкатенации косых черт, и модель формата для порядкового номера, поэтому вам не нужно дополнять его нулями. (И вам на самом деле не нужна переменная, вы можете сделать ту же конструкцию внутри предложения values вставки.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...