Вернул мой курсор в моей функции oracle PL / SLQ, но возвращаются не все строки. Можете ли вы вернуть только 1 строку в функции Oracle pl / sql?

#sql #oracle #plsql

#sql #Oracle #plsql

Вопрос:

Вот мой код, у меня есть 2 строки с одинаковым именем, датой бронирования и идентификатором отеля. Я не понимаю, почему, когда я выполняю эту функцию, она выдает ошибку «точная выборка возвращает больше запрошенного количества строк» вместо того, чтобы возвращать обе мои строки в моей таблице резервирования.

Я полагаю, что курсор вернул правильно, поэтому он должен работать?

 CREATE OR REPLACE FUNCTION findres(cname   IN reservation.cust_name%type,
                                   hotelID IN reservation.hotel_id%type,
                                   resdate IN reservation.reserve_date%type)
  RETURN reservation.reserve_id%type is
   resid reservation.reserve_id%type;
BEGIN
    SELECT reserve_id
      INTO resid
      FROM reservation
     WHERE Cust_name = cname
       AND Hotel_id = hotelID
       AND reserve_date = resdate;
    RETURN resid;

  EXCEPTION
    WHEN no_data_found THEN
      dbms_output.put_line('No reservation found'); 
END;
/
 

Комментарии:

1. Вы возвращаете результаты в одну переменную «resid». Эта переменная может обрабатывать только одно значение. Если ваш запрос возвращает более одного значения, функция выдаст сообщение об ошибке.

Ответ №1:

Из документации для определения into_clause : оператор SELECT INTO извлекает один или несколько столбцов из одной строки и сохраняет их в одной или нескольких скалярных переменных или в одной переменной записи

Затем текущий оператор SELECT следует заменить на случаи возврата более одной строки. Следующие запросы могут быть альтернативами для вашего текущего оператора SQL Select

 SELECT reserve_id
  INTO resid
  FROM
  ( SELECT r.*,
           ROW_NUMBER() OVER (ORDER BY 0) AS rn
      FROM reservation
     WHERE Cust_name = cname
       AND Hotel_id = hotelID
       AND reserve_date = resdate
   )
  WHERE rn = 1;
 

Если версия БД 12 , то используйте

 SELECT reserve_id
  INTO resid
  FROM reservation
 WHERE Cust_name = cname
   AND Hotel_id = hotelID
   AND reserve_date = resdate
 FETCH NEXT 1 ROW ONLY; 
 

без подзапроса, чтобы вернуть только одну строку, учитывая, что вы получаете дубликаты только для этих столбцов без правил упорядочения данных. Благодаря использованию этих запросов нет необходимости обрабатывать no_data_found too_many_rows исключения or.

Обновление: если ваша цель — вернуть все строки, даже если одновременно имеется более одной строки, вы можете использовать SYS_REFCURSOR такие, как

 CREATE OR REPLACE FUNCTION findres(cname   reservation.cust_name%type,
                                   hotelID reservation.hotel_id%type,
                                   resdate reservation.reserve_date%type)
  RETURN SYS_REFCURSOR IS
  recordset SYS_REFCURSOR;
BEGIN
  OPEN recordset FOR
  SELECT reserve_id
    FROM reservation
   WHERE Cust_name = cname
     AND Hotel_id = hotelID 
     AND reserve_date = resdate;

  RETURN recordset;
END;
/
 

и вызвать таким образом, чтобы

 VAR   v_rc REFCURSOR
EXEC :v_rc := findres('Avoras',111,date'2020-12-06');
PRINT v_rc
 

из консоли разработчика SQL.

Комментарии:

1. Похоже, это не то, чего хочет OP. Он действительно хочет вернуть обе строки, если оператор SELECT возвращает две строки. Это можно сделать, но не так, как вы предложили.

2. да, я хотел бы вернуть обе строки, а не только одну из них

3. ну, но он говорит, что вы можете вернуть только 1 строку в функции Oracle pl / sql? @mathguy

4. Да — этот вопрос на правильном английском языке (как его использовал OP) можно перефразировать следующим образом: «правда ли, что в Oracle PL / SQL функция может возвращать только одну строку?» Я полагаю, вы предположили, что это означало что-то другое.

5. ХОРОШО, обновил ответ из-за вашего последнего комментария @Avoras