ORA-01422: точная выборка возвращает больше, чем запрошенное количество строк в RETURNING INTO
У меня есть следующий sql (оракул), который удаляет все строки из таблицы, кроме 100 самых новых.
DELETE FROM my_table tab_outer
WHERE tab_outer.rowid IN (
-- Fetch rowids of rows to delete
SELECT rid FROM (
SELECT rownum r, rid FROM (
SELECT tab.rowid rid
FROM my_table tab
ORDER BY tab.created_date DESC
)
)
-- Delete everything but the 100 nesest rows
WHERE r > 100
)
-- Return newest date that was removed
RETURNING max(tab_outer.created_date) INTO :latestDate
Этот код иногда дает ORA-01422: exact fetch returns more than requested number of rows
утверждая, что в последней дате было добавлено более одной строки. Как это возможно? Агрегирующая функция (max) в предложении RETURNING INTO должна гарантировать, что возвращается только одна строка, нет? Может ли это иметь какое-либо отношение к явному использованию или rowid (я не понимаю, как)?
1 ответ
Я думал, что было невозможно использовать агрегаты в предложении возврата, так как я никогда не пробовал это, и это не упоминается в документации, но на самом деле это работает (11gr2)!!
Смотрите ниже в PL/SQL:
SQL> CREATE TABLE my_table (created_date DATE);
Table created
SQL> INSERT INTO my_table
2 (SELECT SYSDATE + ROWNUM FROM dual CONNECT BY LEVEL <= 500);
500 rows inserted
SQL> DECLARE
2 latestDate DATE;
3 BEGIN
4 DELETE FROM my_table tab_outer
5 WHERE tab_outer.rowid IN (
6 -- Fetch rowids of rows to delete
7 SELECT rid FROM (
8 SELECT rownum r, rid FROM (
9 SELECT tab.rowid rid
10 FROM my_table tab
11 ORDER BY tab.created_date DESC
12 )
13 )
14 -- Delete everything but the 100 nesest rows
15 WHERE r > 100
16 )
17 -- Return newest date that was removed
18 RETURNING max(tab_outer.created_date) INTO latestDate;
19 dbms_output.put_line(latestDate);
20 END;
21 /
06/08/14
И даже в SQL*Plus (клиент 10.2.0.1.0, база данных 11.2.0.3.0):
SQL> VARIABLE latestDate VARCHAR2(20);
SQL> DELETE FROM my_table tab_outer
2 WHERE tab_outer.rowid IN (
3 -- Fetch rowids of rows to delete
4 SELECT rid FROM (
5 SELECT rownum r, rid FROM (
6 SELECT tab.rowid rid
7 FROM my_table tab
8 ORDER BY tab.created_date DESC
9 )
10 )
11 -- Delete everything but the 100 nesest rows
12 WHERE r > 100
13 )
14 -- Return newest date that was removed
15 RETURNING max(tab_outer.created_date) INTO :latestDate;
400 rows deleted.
SQL> select :latestDate from dual;
:LATESTDATE
--------------------------------------------------------------------------------
06/08/14
Можете ли вы опубликовать полный пример и вашу версию базы данных / клиента.