如何使用计算值更新具有 PL\SQL 的列
How can I update a column with PL\SQL by using a calculated value
我出于学习目的创建了一个虚拟数据库,并且我有意在其中一个表中创建了一些重复的记录。在每种情况下,我都想将其中一条重复记录标记为 Latest='Y',将另一条记录标记为 'N',对于每条记录,Latest 标记将是 'Y'.
我尝试使用 PlSQL 遍历我的所有记录,但是当我尝试使用之前计算的值(这表明它是重复的记录)时,它说:
ORA-06550:第 20 行,第 17 列:
PLS-00201: 必须声明标识符 'COUNTER'
这是我尝试使用的语句:
DECLARE
CURSOR cur
IS
SELECT order_id, order_date, person_id,
amount, successfull_order, country_id, latest, ROWCOUNT AS COUNTER
FROM (SELECT order_id,
order_date,
person_id,
amount,
successfull_order,
country_id,
latest,
ROW_NUMBER () OVER (PARTITION BY order_id, order_date,
person_id, amount, successfull_order, country_id
ORDER BY order_id, order_date,
person_id, amount, successfull_order, country_id) ROWCOUNT
FROM orders) orders
FOR UPDATE OF orders.latest;
rec cur%ROWTYPE;
BEGIN
FOR rec IN cur
LOOP
IF MOD (COUNTER, 2) = 0
THEN
UPDATE orders
SET latest = 'N'
WHERE CURRENT OF cur;
ELSE
UPDATE orders
SET latest = 'Y'
WHERE CURRENT OF cur;
END IF;
END LOOP;
END;
我是 PlSQL 的新手,所以我尝试修改我在这里找到的语句:
http://www.adp-gmbh.ch/ora/plsql/cursors/for_update.html
我应该在声明中更改什么,或者我应该使用不同的方法?
提前感谢您的回答!
博通
您需要声明变量 COUNTER,然后需要在循环中维护(即递增)它。
我怀疑你的例子只是为了学习PL/SQL。但是请注意,与使用游标循环相比,使用单个 SQL 语句执行操作通常性能更高。
您在光标中将 ROWNUM
称为 COUNTER
。
获取时,您应该从游标引用访问它,如 MOD (rec.COUNTER, 2)
您的问题是 COUNTER
是游标记录 rec
的属性,而不是 PL/SQL 变量。所以:
IF MOD (COUNTER, 2) = 0
应该是:
IF MOD (rec.COUNTER, 2) = 0
但是,您不需要使用 PL/SQL 或游标,它可以在单个 MERGE
语句中完成:
Oracle 设置:
CREATE TABLE orders ( order_id, order_date, latest ) AS
SELECT 1, DATE '2017-01-01', CAST( NULL AS CHAR(1) ) FROM DUAL UNION ALL
SELECT 1, DATE '2017-01-02', NULL FROM DUAL UNION ALL
SELECT 1, DATE '2017-01-03', NULL FROM DUAL UNION ALL
SELECT 2, DATE '2017-01-04', NULL FROM DUAL UNION ALL
SELECT 2, DATE '2017-01-01', NULL FROM DUAL UNION ALL
SELECT 3, DATE '2017-01-06', NULL FROM DUAL;
更新声明:
MERGE INTO orders dst
USING ( SELECT ROW_NUMBER() OVER ( PARTITION BY order_id
ORDER BY order_date DESC ) AS rn
FROM orders
) src
ON ( src.ROWID = dst.ROWID )
WHEN MATCHED THEN
UPDATE SET latest = CASE src.rn WHEN 1 THEN 'Y' ELSE 'N' END;
输出:
SELECT * FROM orders;
ORDER_ID ORDER_DATE LATEST
-------- ---------- ------
1 2017-01-01 N
1 2017-01-02 N
1 2017-01-03 Y
2 2017-01-04 Y
2 2017-01-01 N
3 2017-01-06 Y
我出于学习目的创建了一个虚拟数据库,并且我有意在其中一个表中创建了一些重复的记录。在每种情况下,我都想将其中一条重复记录标记为 Latest='Y',将另一条记录标记为 'N',对于每条记录,Latest 标记将是 'Y'.
我尝试使用 PlSQL 遍历我的所有记录,但是当我尝试使用之前计算的值(这表明它是重复的记录)时,它说:
ORA-06550:第 20 行,第 17 列: PLS-00201: 必须声明标识符 'COUNTER'
这是我尝试使用的语句:
DECLARE
CURSOR cur
IS
SELECT order_id, order_date, person_id,
amount, successfull_order, country_id, latest, ROWCOUNT AS COUNTER
FROM (SELECT order_id,
order_date,
person_id,
amount,
successfull_order,
country_id,
latest,
ROW_NUMBER () OVER (PARTITION BY order_id, order_date,
person_id, amount, successfull_order, country_id
ORDER BY order_id, order_date,
person_id, amount, successfull_order, country_id) ROWCOUNT
FROM orders) orders
FOR UPDATE OF orders.latest;
rec cur%ROWTYPE;
BEGIN
FOR rec IN cur
LOOP
IF MOD (COUNTER, 2) = 0
THEN
UPDATE orders
SET latest = 'N'
WHERE CURRENT OF cur;
ELSE
UPDATE orders
SET latest = 'Y'
WHERE CURRENT OF cur;
END IF;
END LOOP;
END;
我是 PlSQL 的新手,所以我尝试修改我在这里找到的语句: http://www.adp-gmbh.ch/ora/plsql/cursors/for_update.html
我应该在声明中更改什么,或者我应该使用不同的方法?
提前感谢您的回答! 博通
您需要声明变量 COUNTER,然后需要在循环中维护(即递增)它。 我怀疑你的例子只是为了学习PL/SQL。但是请注意,与使用游标循环相比,使用单个 SQL 语句执行操作通常性能更高。
您在光标中将 ROWNUM
称为 COUNTER
。
获取时,您应该从游标引用访问它,如 MOD (rec.COUNTER, 2)
您的问题是 COUNTER
是游标记录 rec
的属性,而不是 PL/SQL 变量。所以:
IF MOD (COUNTER, 2) = 0
应该是:
IF MOD (rec.COUNTER, 2) = 0
但是,您不需要使用 PL/SQL 或游标,它可以在单个 MERGE
语句中完成:
Oracle 设置:
CREATE TABLE orders ( order_id, order_date, latest ) AS
SELECT 1, DATE '2017-01-01', CAST( NULL AS CHAR(1) ) FROM DUAL UNION ALL
SELECT 1, DATE '2017-01-02', NULL FROM DUAL UNION ALL
SELECT 1, DATE '2017-01-03', NULL FROM DUAL UNION ALL
SELECT 2, DATE '2017-01-04', NULL FROM DUAL UNION ALL
SELECT 2, DATE '2017-01-01', NULL FROM DUAL UNION ALL
SELECT 3, DATE '2017-01-06', NULL FROM DUAL;
更新声明:
MERGE INTO orders dst
USING ( SELECT ROW_NUMBER() OVER ( PARTITION BY order_id
ORDER BY order_date DESC ) AS rn
FROM orders
) src
ON ( src.ROWID = dst.ROWID )
WHEN MATCHED THEN
UPDATE SET latest = CASE src.rn WHEN 1 THEN 'Y' ELSE 'N' END;
输出:
SELECT * FROM orders;
ORDER_ID ORDER_DATE LATEST
-------- ---------- ------
1 2017-01-01 N
1 2017-01-02 N
1 2017-01-03 Y
2 2017-01-04 Y
2 2017-01-01 N
3 2017-01-06 Y