#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