Oracle выбирает переменную, ОШИБКА ORA-00947 недостаточно значений

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

Вместо того, чтобы пытаться открыть курсор (что мне тоже не удалось сделать должным образом), я подумал, что, может быть, я мог бы сделать это с помощью выбора временной таблицы и сохранить значение, пока я заполняю курсор. Может быть, это невозможно, но моя ошибка не имеет для меня смысла.

Вот мой упрощенный код, я разбил оператор count, чтобы лучше определить, где именно была ошибка.

V_ASN_COUNT           NUMBER;

OPEN O_CURSOR FOR  
  WITH O_LIST AS(
     SELECT *
       FROM AN_ORDER_INFO OI, AN_SHIPMENT_INFO SI
       -- where bunch of stuff
  ),   
  COUNT_ASN_NO AS  (
          SELECT COUNT(DISTINCT ASN_NO) AS "ASN_COUNT"
          FROM O_LIST 
  ),
  SAVE_ASN_COUNT AS (
   SELECT ASN_COUNT
   INTO V_ASN_COUNT
   FROM COUNT_ASN_NO -- error on this line, not enough values, its just 1:1, i dont get it?
  ) 
  SELECT * FROM O_LIST;   

IF(V_ASN_COUNT > 1) THEN
    RAISE MULTIPLE_ASNS;
END IF;   

Или, возможно, мне нужно открыть курсор после этого и сделать что-то подобное, за исключением того, что я знаю, что это неправильно, я получаю сообщение об ошибке «Ожидается BULK INTO»:

  OPEN O_CURSOR; 
      LOOP
          FETCH COUNT(DISTINCT ASN_NO) INTO V_ASN_COUNT;
          EXIT WHEN ASN_NO%NOTFOUND;
      END LOOP;
  CLOSE O_CURSOR;

person SomeRandomDeveloper    schedule 15.10.2014    source источник


Ответы (1)


У вас не может быть into в середине оператора курсора; это то, что вызывает исключение. Если бы ваш o_list CTE выбирал только одно значение, тогда это выполнялось бы, но v_asn_count впоследствии все равно было бы нулевым. При выборе нескольких столбцов в o_list он получает ORA-00947. (Возможно, это ошибка синтаксического анализатора; возможно, он должен либо выдавать ошибку только потому, что есть предложение into, либо использовать список выбора из правильного запроса CTE).

На самом деле не совсем ясно, нужен ли вам курсор вообще и вы пытаетесь уменьшить дублирование кода, но похоже, что вы действительно просто хотите сделать:

SELECT COUNT(DISTINCT ASN_NO)
INTO V_ASN_COUNT
FROM AN_ORDER_INFO OI, AN_SHIPMENT_INFO SI
-- where bunch of stuff
;

IF(V_ASN_COUNT > 1) THEN
  RAISE MULTIPLE_ASNS;
END IF;

(Ваш where bunch of stuff предположительно включает условия соединения; это не по теме, но вы можете подумать об использовании синтаксиса соединения ANSI).

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

Или, если ваша обработка, в частности выборка, позволяет это сделать, вы можете добавить аналитический счетчик к существующему запросу курсора:

COUNT(DISTINCT dummy) OVER (PARTITION BY NULL) AS ASN_COUNT

... что даст вам количество различных значений asn_no во всем наборе результатов в виде дополнительного столбца в каждой строке этого набора результатов. Затем вы можете проверить это число после первой выборки, прежде чем делать что-либо еще, и вызвать исключение в этот момент.

Это не сработает, если вам нужно считать в этой процедуре, но возвращать курсор другой процедуре/вызывающему; вызывающая сторона должна будет проверить результаты и вызвать исключение, что, вероятно, не так, как вы видите, как это работает.

person Alex Poole    schedule 15.10.2014
comment
Спасибо Алекс, я возвращаю курсор из хранимой процедуры. В o_list есть то, что я возвращаю, если я не сталкиваюсь со случаем, когда несколько поставщиков отправляют один и тот же номер ASN. Мне пришлось бы выполнить этот запрос дважды, один раз для подсчета и один раз, чтобы получить мой список. И поэтому похоже, что открытие моего курсора было бы более эффективным в этом случае, но возникли проблемы с синтаксисом и поиском правильного примера ресурса. - person SomeRandomDeveloper; 15.10.2014
comment
Это не обязательно будет более эффективным, но уменьшит дублирование кода и, следовательно, обслуживание, а также риск того, что один запрос будет изменен, а другой пропущен. - person Alex Poole; 15.10.2014
comment
Я тоже именно так и думал. Я обновил свой вопрос, указав мои текущие спотыкания при открытии курсора, поскольку сейчас это кажется реальной проблемой. Возможно, мне следует изменить название этого вопроса, чтобы оно было более подходящим. - person SomeRandomDeveloper; 15.10.2014
comment
Может быть, было бы проще добавить счетчик в основной запрос по разделу, как вы предложили, попробуем. - person SomeRandomDeveloper; 15.10.2014
comment
Я думаю, что это отвечает на фактический вопрос, который я задал о своей ошибке. Как добиться этого с помощью курсора - это другой вопрос, который я разместил здесь: stackoverflow.com/questions/26388104/ - person SomeRandomDeveloper; 15.10.2014
comment
Я начал обновлять этот ответ некоторым кодом, но вы абсолютно правы, сделав его новым вопросом. Вместо этого я разместил свой код *8-) - person Alex Poole; 15.10.2014