使用 Oracle/PLSQL 中的过程删除重复记录
Delete duplicated records using procedure in Oracle/PLSQL
正如标题,我想在 Oracle/PLSQL 中创建一个过程来删除在某些列中共享相同值的行。我知道如何使用查询来实现它,但是如何使用过程来实现呢?我必须使用任何循环吗?我对 PLSQL 很陌生
请帮忙,非常感谢!
如果您知道如何在 SQL 中进行操作,最好在 sql 中进行操作。 PL/SQL 仅当您无法在 SQL 语句中编写特定任务或查询中存在性能问题并且可以通过在 PL/SQL 中编写逻辑来改进时才应使用(第二种情况非常罕见).
如果你想写PL/SQL过程来参数化,这样任何table都可以被传递来删除其中的重复项,那么这是有意义的。您需要在过程中动态生成删除语句并使用 execute immediate
.
执行
如果你的目的是学习PL/SQL,那就是编程语言,你需要像学习新的编程语言一样花一些时间。
如果您想要一个简单的过程从特定的 table 中删除,您可以使用下面的代码:
CREATE OR REPLACE PROCEDURE DELETE_DUPLICATE AS
BEGIN
FOR I IN (SELECT TAB.A, TAB.B, MIN(ROWID) RID
FROM DUPLICATE_TABLE TAB
GROUP BY TAB.A, TAB.B
HAVING COUNT(*) > 1) LOOP
DELETE FROM DUPLICATE_TABLE TAB
WHERE I.RID <> TAB.ROWID
AND TAB.A = I.A
AND TAB.B = I.B;
COMMIT;
END LOOP;
END;
这里DUPLICATE_TABLE是table有重复值。我们正在删除 A 列和 B 列中具有相同值的行。
不建议使用 plsql 来完成可以使用普通 sql 完成的事情。
每当你有 sql 和 plsql 的组合时,你就是在 sql 和 plsql 引擎之间切换。因此,在没有适当要求的情况下产生这种开销是没有意义的。
如果出于某种原因仍然需要这样做,您至少可以实施批量删除以减少一些开销。请参考下面的代码以了解如何做到这一点 -
DECLARE
TYPE t_del IS TABLE OF VARCHAR2(100);
l_del t_del;
CURSOR c IS
SELECT MIN(ROWID) RID
FROM test_tbl TAB
GROUP BY TAB.age, TAB.gender
HAVING COUNT(*) > 1;
BEGIN
OPEN c;
LOOP
FETCH c BULK COLLECT INTO l_del;
EXIT WHEN l_del.COUNT = 0;
FORALL i IN l_del.FIRST..l_del.last
DELETE FROM test_tbl WHERE ROWID = l_del(i);
END LOOP;
END;
Hey. As per your question, although it is not advicable to create
procedure for this simpler task which can be easily done via Pure SQL.
But if its really imp to make it as a stored procedure then i would
suggest to use PURE SQL logic than using any kind of loop as there
will be Context Switching which will have a toll on the database.
Below is a snippet which i think will be useful also incorporated
Analytical function to suffice your issue. Let me know if it helps.
CREATE OR REPLACE PROCEDURE Dup_DELETE
AS
BEGIN
DELETE
FROM EMP
WHERE EMP.ROWID IN
-- Assuming that i am trying to segregate the duplicate values on Empno and ename
(SELECT A.ROWID
FROM
(SELECT ROW_NUMBER() OVER(PARTITION BY EMPNO,ENAME ORDER BY JOB DESC) RNK,
empno,
ename,
rowid
FROM EMP
)A
WHERE A.RNK <> 1
);
END;
只需将您的 SQL 语句放入过程中即可。没有规则说你必须改变方法,因为它是 PL/SQL。例如,
create or replace procedure dedupe_sometable
as
begin
delete sometable
where rowid in
( select lag(rowid) over (partition by id order by null)
from sometable );
end dedupe_sometable;
根据需要添加日志记录等。
(理想情况下,这将在一个包中而不是一个独立的过程中。)
正如标题,我想在 Oracle/PLSQL 中创建一个过程来删除在某些列中共享相同值的行。我知道如何使用查询来实现它,但是如何使用过程来实现呢?我必须使用任何循环吗?我对 PLSQL 很陌生
请帮忙,非常感谢!
如果您知道如何在 SQL 中进行操作,最好在 sql 中进行操作。 PL/SQL 仅当您无法在 SQL 语句中编写特定任务或查询中存在性能问题并且可以通过在 PL/SQL 中编写逻辑来改进时才应使用(第二种情况非常罕见).
如果你想写PL/SQL过程来参数化,这样任何table都可以被传递来删除其中的重复项,那么这是有意义的。您需要在过程中动态生成删除语句并使用 execute immediate
.
如果你的目的是学习PL/SQL,那就是编程语言,你需要像学习新的编程语言一样花一些时间。
如果您想要一个简单的过程从特定的 table 中删除,您可以使用下面的代码:
CREATE OR REPLACE PROCEDURE DELETE_DUPLICATE AS
BEGIN
FOR I IN (SELECT TAB.A, TAB.B, MIN(ROWID) RID
FROM DUPLICATE_TABLE TAB
GROUP BY TAB.A, TAB.B
HAVING COUNT(*) > 1) LOOP
DELETE FROM DUPLICATE_TABLE TAB
WHERE I.RID <> TAB.ROWID
AND TAB.A = I.A
AND TAB.B = I.B;
COMMIT;
END LOOP;
END;
这里DUPLICATE_TABLE是table有重复值。我们正在删除 A 列和 B 列中具有相同值的行。
不建议使用 plsql 来完成可以使用普通 sql 完成的事情。 每当你有 sql 和 plsql 的组合时,你就是在 sql 和 plsql 引擎之间切换。因此,在没有适当要求的情况下产生这种开销是没有意义的。
如果出于某种原因仍然需要这样做,您至少可以实施批量删除以减少一些开销。请参考下面的代码以了解如何做到这一点 -
DECLARE
TYPE t_del IS TABLE OF VARCHAR2(100);
l_del t_del;
CURSOR c IS
SELECT MIN(ROWID) RID
FROM test_tbl TAB
GROUP BY TAB.age, TAB.gender
HAVING COUNT(*) > 1;
BEGIN
OPEN c;
LOOP
FETCH c BULK COLLECT INTO l_del;
EXIT WHEN l_del.COUNT = 0;
FORALL i IN l_del.FIRST..l_del.last
DELETE FROM test_tbl WHERE ROWID = l_del(i);
END LOOP;
END;
Hey. As per your question, although it is not advicable to create procedure for this simpler task which can be easily done via Pure SQL. But if its really imp to make it as a stored procedure then i would suggest to use PURE SQL logic than using any kind of loop as there will be Context Switching which will have a toll on the database. Below is a snippet which i think will be useful also incorporated Analytical function to suffice your issue. Let me know if it helps.
CREATE OR REPLACE PROCEDURE Dup_DELETE
AS
BEGIN
DELETE
FROM EMP
WHERE EMP.ROWID IN
-- Assuming that i am trying to segregate the duplicate values on Empno and ename
(SELECT A.ROWID
FROM
(SELECT ROW_NUMBER() OVER(PARTITION BY EMPNO,ENAME ORDER BY JOB DESC) RNK,
empno,
ename,
rowid
FROM EMP
)A
WHERE A.RNK <> 1
);
END;
只需将您的 SQL 语句放入过程中即可。没有规则说你必须改变方法,因为它是 PL/SQL。例如,
create or replace procedure dedupe_sometable
as
begin
delete sometable
where rowid in
( select lag(rowid) over (partition by id order by null)
from sometable );
end dedupe_sometable;
根据需要添加日志记录等。
(理想情况下,这将在一个包中而不是一个独立的过程中。)