Create Some Test Data
CREATE TABLE parts
(
part_number INTEGER
, part_name VARCHAR2 (100)
)
Table created.
BEGIN
INSERT INTO parts
VALUES (1, 'Mouse');
INSERT INTO parts
VALUES (100, 'Keyboard');
INSERT INTO parts
VALUES (500, 'Monitor');
COMMIT;
END;
Statement processed.
Which rows did I update? (the wrong way)
DECLARE
l_num PLS_INTEGER;
BEGIN
UPDATE parts
SET part_name = UPPER (part_name)
WHERE part_name LIKE 'K%';
SELECT part_number
INTO l_num
FROM parts
WHERE part_name = UPPER (part_name);
DBMS_OUTPUT.put_line (l_num);
END;
Statement processed.
100
Which rows did I update? (the right way)
DECLARE
l_num PLS_INTEGER;
BEGIN
UPDATE parts
SET part_name = UPPER (part_name)
WHERE part_name LIKE 'K%'
RETURNING part_number
INTO l_num;
DBMS_OUTPUT.put_line (l_num);
END;
Statement processed.
100
Or maybe we could do this....
CREATE TABLE parts_copy
AS
SELECT * FROM parts
Table created.
What rows were changed? Let's MINUS that! (ugh)
BEGIN
UPDATE parts
SET part_name = part_name || '1';
FOR rec IN (SELECT part_number, part_name FROM parts
MINUS
SELECT part_number, part_name FROM parts_copy)
LOOP
DBMS_OUTPUT.put_line (rec.part_number);
END LOOP;
END;
Statement processed.
1
100
500
Use RETURNING with BULK COLLECT INTO when changing multiple rows
DECLARE
l_part_numbers DBMS_SQL.number_table;
BEGIN
UPDATE parts
SET part_name = part_name || '1'
RETURNING part_number
BULK COLLECT INTO l_part_numbers;
FOR indx IN 1 .. l_part_numbers.COUNT
LOOP
DBMS_OUTPUT.put_line (l_part_numbers (indx));
END LOOP;
END;
Statement processed.
1
100
500
Return an entire row? Not with ROW keyword.
DECLARE
l_part parts%ROWTYPE;
BEGIN
UPDATE parts
SET part_number = -1 * part_number, part_name = UPPER (part_name)
WHERE part_number = 1
RETURNING ROW
INTO l_part;
DBMS_OUTPUT.put_line (l_part.part_name);
END;
ORA-06550: line 7, column 14: PL/SQL: ORA-00904: "ROW": invalid identifierMore Details: https://docs.oracle.com/error-help/db/ora-06550
Populate record in RETURNING with list of columns
DECLARE
l_part parts%ROWTYPE;
BEGIN
UPDATE parts
SET part_number = -1 * part_number, part_name = UPPER (part_name)
WHERE part_number = 1
RETURNING part_number, part_name
INTO l_part;
DBMS_OUTPUT.put_line (l_part.part_name);
END;
Statement processed.
MOUSE11
More test data
CREATE TABLE employees
(
employee_id INTEGER
, last_name VARCHAR2 (100)
, salary NUMBER
)
Table created.
BEGIN
INSERT INTO employees
VALUES (100, 'Gutseriev', 1000);
INSERT INTO employees
VALUES (200, 'Ellison', 2000);
INSERT INTO employees
VALUES (400, 'Gates', 3000);
INSERT INTO employees
VALUES (500, 'Buffet', 4000);
INSERT INTO employees
VALUES (600, 'Slim', 5000);
INSERT INTO employees
VALUES (700, 'Arnault', 6000);
COMMIT;
END;
Statement processed.
Need aggregate information about impact of DML?
DECLARE
l_total INTEGER;
BEGIN
UPDATE employees
SET salary = salary * 2
WHERE INSTR (last_name, 'e') > 0;
SELECT SUM (salary)
INTO l_total
FROM employees
WHERE INSTR (last_name, 'e') > 0;
DBMS_OUTPUT.put_line (l_total);
END;
Statement processed.
16000
You could perform a computation in PL/SQL....
DECLARE
l_salaries DBMS_SQL.number_table;
l_total INTEGER := 0;
BEGIN
UPDATE employees
SET salary = salary * 2
WHERE INSTR (last_name, 'e') > 0
RETURNING salary
BULK COLLECT INTO l_salaries;
FOR indx IN 1 .. l_salaries.COUNT
LOOP
l_total := l_total + l_salaries (indx);
END LOOP;
DBMS_OUTPUT.put_line (l_total);
END;
Statement processed.
32000
Call aggregate function in RETURNING clause!
DECLARE
l_total INTEGER;
BEGIN
UPDATE employees
SET salary = salary * 2
WHERE INSTR (last_name, 'e') > 0
RETURNING SUM (salary)
INTO l_total;
DBMS_OUTPUT.put_line (l_total);
END;
Statement processed.
64000
Use RETURNING with EXECUTE IMMEDIATE
DECLARE
l_part_number parts.part_number%TYPE;
BEGIN
EXECUTE IMMEDIATE
q'[UPDATE parts
SET part_name = part_name || '1'
WHERE part_number = 100
RETURNING part_number INTO :one_pn]'
RETURNING INTO l_part_number;
DBMS_OUTPUT.put_line (l_part_number);
END;
Statement processed.
100
RETURNING Multiple Rows in EXECUTE IMMEDIATE
DECLARE
l_part_numbers DBMS_SQL.number_table;
BEGIN
EXECUTE IMMEDIATE
q'[UPDATE parts
SET part_name = part_name || '1'
RETURNING part_number INTO :pn_list]'
RETURNING BULK COLLECT INTO l_part_numbers;
FOR indx IN 1 .. l_part_numbers.COUNT
LOOP
DBMS_OUTPUT.put_line (l_part_numbers (indx));
END LOOP;
END;
Statement processed.
-1
100
500