Я пытаюсь выбрать данные в процедуре Oracle PL/SQL. Когда я выбираю данные из таблицы напрямую вот так
SELECT * FROM CUSTOMER_USERS
WHERE customer_id = 'cust1234'
AND user_id = 'cust1234user'
Я получаю одну строку данных.
Однако, когда я помещаю те же точные условия в запрос выбора с переменными, это вызывает ошибку с описанием «ORA-01422: точная выборка возвращает больше, чем запрошенное количество строк».
customerID := 'cust1234';
userID := 'cust1234user';
SELECT CUST_API_KEY INTO v_encValue
FROM CUSTOMER_USERS
WHERE customer_id = customerID
AND userid = userID;
Как это могло произойти? Эти два столбца составляют ПК, поэтому в этой таблице даже не может быть дубликатов по этим критериям. Я не могу сказать, что он думает о дополнительных строках.
Это объясняется в документации:
Если инструкция SQL ссылается на имя, которое принадлежит как столбцу, так и локальной переменной или формальному параметру, то имя столбца имеет приоритет.
Итак, когда вы это сделаете:
AND userid = userID
обе эти ссылки userid
относятся к столбцу таблицы; ни то, ни другое не относится к переменной PL/SQL. Таким образом, это условие считается истинным, по крайней мере, для каждой строки, где userid
не равно нулю. Обратите внимание, что по умолчанию немного другой случай не имеет значения; вы только что избежали той же проблемы с customer_id
и customerID
, добавив к ним подчеркивание.
Сделайте имена переменных PL/SQL отличными от имен столбцов. Обычно к переменным добавляют какой-нибудь префикс (например, l_userid
), и если вы это сделаете, то установите соглашение об именах для вашего кода. В сохраненном блоке PL/SQL вы также можете указать переменные с именем блока (например, именем процедуры) и именем/псевдонимом таблицы — некоторые люди предпочитают это.
Ух ты, совершенно тупая ошибка. Вот к чему приводит попытка что-то сделать в конце 12-часового рабочего дня. Спасибо и MT0 за ваши ответы.
Когда вы используете идентификатор, Oracle попытается найти значение этого идентификатора из локальной области - в данном случае с помощью SQL-запроса. Если он не найдет его, он проверит значения идентификаторов во внешних областях (например, переменных PL/SQL). Итак, ваш запрос:
SELECT CUST_API_KEY INTO v_encValue
FROM CUSTOMER_USERS
WHERE customer_id = customerID
AND userid = userID;
фактически то же самое, что:
SELECT CUST_API_KEY INTO v_encValue
FROM CUSTOMER_USERS u
WHERE u.customer_id = customerID
AND u.userid = u.userID;
Где userID
— это значение столбца, а НЕ переменная PL/SQL.
Всегда называйте переменные иначе, чем идентификаторы столбцов.
DECLARE
v_customerID CUSTOMER_USERS.CUSTOMER_ID%TYPE := 'cust1234';
v_userID CUSTOMER_USERS.USERID%TYPE := 'cust1234user';
v_encValue CUSTOMER_USERS.CUST_API_KEY%TYPE;
BEGIN
SELECT CUST_API_KEY
INTO v_encValue
FROM CUSTOMER_USERS
WHERE customer_id = v_customerID
AND userid = v_userID;
END;
/
userid
иuserID
идентичны, и, скорее всего, это умножает возвращаемые строки