在其他两个游标中找到游标时如何从表中删除
Posted
技术标签:
【中文标题】在其他两个游标中找到游标时如何从表中删除【英文标题】:How to delete from a table when a cursor is found in two other cursors 【发布时间】:2014-07-28 14:25:46 【问题描述】:下面是三个不同的游标:POTENTIAL_USERS、NO_WORKFLOWS 和 NO_MAPPINGS。我试图找到一种方法从 NO_MAPPINGS 和 NO_WORKFLOWS 游标中找到的 POTENTIAL USERS CURSOR 中删除。我使用游标是因为它们引用的查询相当长,这使我更容易理解。此外,NO_WORKFLOWS 和 NO_MAPPINGS 引用了两个不同的 WITH 语句,因为我在只读数据库中,所以我用它们替换而不是使用视图,并且 POTENTIAL_USERS 引用了一个提取非活动用户帐户的查询。我收集了在另一个数据库中创建类似场景的错误消息。如有任何意见或建议,我将不胜感激。
CURSOR USERS_WITHOUT_CHECKEDOUT_WORKFLOWS
IS
WITH POTENTIAL_USERS_TO_DELETE
AS (SELECT USER_NAME, USER_ID
FROM GAI_PM.REP_USERS
WHERE USER_NAME NOT IN
(SELECT USER_NAME
FROM (SELECT ROW_NUMBER ()
OVER (
PARTITION BY REP_USERS.USER_NAME
ORDER BY
TO_DATE (
SUBSTR (
LAST_SAVED,
1,
10),
'MM/DD/YYYY') DESC)
RN,
REP_USERS.USER_NAME,
REP_VERSION_PROPS.LAST_SAVED
FROM GAI_PM.REP_USERS
JOIN
GAI_PM.REP_VERSION_PROPS
ON REP_USERS.USER_ID =
REP_VERSION_PROPS.USER_ID)
WHERE RN = 1
AND TO_DATE (SUBSTR (LAST_SAVED, 1, 10),
'MM/DD/YYYY') >
ADD_MONTHS (TRUNC (SYSDATE), -12))
AND UPPER (REP_USERS.USER_NAME) NOT LIKE '%ADMIN%'
AND UPPER (REP_USERS.USER_NAME) NOT LIKE
'%CSTEINKAMP%'),
CHECKED_OUT_WORKFLOWS
AS (SELECT C.SUBJ_NAME,
A.TASK_NAME,
B.USER_NAME,
USER_ID
FROM GAI_PM.OPB_TASK A
JOIN GAI_PM.OPB_USERS B
ON A.CHECKOUT_USER_ID = B.USER_ID
JOIN GAI_PM.OPB_SUBJECT C
ON A.SUBJECT_ID = C.SUBJ_ID
WHERE A.CHECKOUT_USER_ID <> 0)
SELECT DISTINCT POTENTIAL_USERS_TO_DELETE.USER_NAME
FROM POTENTIAL_USERS_TO_DELETE
LEFT JOIN
CHECKED_OUT_WORKFLOWS
ON POTENTIAL_USERS_TO_DELETE.USER_ID =
CHECKED_OUT_WORKFLOWS.USER_ID
WHERE CHECKED_OUT_WORKFLOWS.USER_NAME IS NULL;
CURSOR POTENTIAL_USERS_TO_DELETE
IS
SELECT USER_NAME AS "USERS TO DELETE"
FROM GAI_PM.REP_USERS
WHERE USER_NAME NOT IN
(SELECT USER_NAME
FROM (SELECT ROW_NUMBER ()
OVER (
PARTITION BY REP_USERS.USER_NAME
ORDER BY
TO_DATE (
SUBSTR (
LAST_SAVED,
1,
10),
'MM/DD/YYYY') DESC)
RN,
REP_USERS.USER_NAME,
REP_VERSION_PROPS.LAST_SAVED
FROM GAI_PM.REP_USERS
JOIN
GAI_PM.REP_VERSION_PROPS
ON REP_USERS.USER_ID =
REP_VERSION_PROPS.USER_ID)
WHERE RN = 1
AND TO_DATE (SUBSTR (LAST_SAVED, 1, 10),
'MM/DD/YYYY') >
ADD_MONTHS (TRUNC (SYSDATE), -12))
AND UPPER (REP_USERS.USER_NAME) NOT LIKE '%ADMIN%'
AND UPPER (REP_USERS.USER_NAME) NOT LIKE '%CSTEINKAMP%';
BEGIN
DECLARE
CURSOR USERS_WITHOUT_CHECKEDOUT_MAPPINGS
IS
WITH POTENTIAL_USERS_TO_DELETE
AS (SELECT USER_NAME, USER_ID
FROM GAI_PM.REP_USERS
WHERE USER_NAME NOT IN
(SELECT USER_NAME
FROM (SELECT ROW_NUMBER ()
OVER (
PARTITION BY REP_USERS.USER_NAME
ORDER BY
TO_DATE (
SUBSTR (
LAST_SAVED,
1,
10),
'MM/DD/YYYY') DESC)
RN,
REP_USERS.USER_NAME,
REP_VERSION_PROPS.LAST_SAVED
FROM GAI_PM.REP_USERS
JOIN
GAI_PM.REP_VERSION_PROPS
ON REP_USERS.USER_ID =
REP_VERSION_PROPS.USER_ID)
WHERE RN = 1
AND TO_DATE (SUBSTR (LAST_SAVED, 1, 10),
'MM/DD/YYYY') >
ADD_MONTHS (TRUNC (SYSDATE), -12))
AND UPPER (REP_USERS.USER_NAME) NOT LIKE '%ADMIN%'
AND UPPER (REP_USERS.USER_NAME) NOT LIKE
'%CSTEINKAMP%'),
CHECKED_OUT_MAPPINGS
AS (SELECT C.SUBJ_NAME,
A.MAPPING_NAME,
B.USER_NAME,
B.USER_ID
FROM GAI_PM.OPB_MAPPING A
JOIN GAI_PM.OPB_USERS B
ON A.CHECKOUT_USER_ID = B.USER_ID
JOIN GAI_PM.OPB_SUBJECT C
ON A.SUBJECT_ID = C.SUBJ_ID
WHERE A.CHECKOUT_USER_ID <> 0)
SELECT DISTINCT POTENTIAL_USERS_TO_DELETE.USER_NAME, MAPPING_NAME
FROM POTENTIAL_USERS_TO_DELETE
LEFT JOIN
CHECKED_OUT_MAPPINGS
ON POTENTIAL_USERS_TO_DELETE.USER_ID =
CHECKED_OUT_MAPPINGS.USER_ID
WHERE CHECKED_OUT_MAPPINGS.USER_NAME IS NULL;
POTENTIAL_USERS POTENTIAL_USERS_TO_DELETE%ROWTYPE;
NO_WORKFLOWS USERS_WITHOUT_CHECKEDOUT_WORKFLOWS%ROWTYPE;
NO_MAPPINGS USERS_WITHOUT_CHECKEDOUT_MAPPINGS%ROWTYPE;
BEGIN
LOOP
IF NOT (POTENTIAL_USERS_TO_DELETE%ISOPEN)
THEN
OPEN POTENTIAL_USERS_TO_DELETE;
END IF;
IF NOT (USERS_WITHOUT_CHECKEDOUT_WORKFLOWS%ISOPEN)
THEN
OPEN USERS_WITHOUT_CHECKEDOUT_WORKFLOWS;
END IF;
IF NOT (USERS_WITHOUT_CHECKEDOUT_MAPPINGS%ISOPEN)
THEN
OPEN USERS_WITHOUT_CHECKEDOUT_MAPPINGS;
END IF;
FETCH POTENTIAL_USERS_TO_DELETE INTO POTENTIAL_USERS;
FETCH USERS_WITHOUT_CHECKEDOUT_WORKFLOWS INTO NO_WORKFLOWS;
FETCH USERS_WITHOUT_CHECKEDOUT_MAPPINGS INTO NO_MAPPINGS;
DELETE FROM POTENTIAL_USERS
WHERE POTENTIAL_USERS.USER_NAME = NO_WORKFLOWS.USER_NAME
OR POTENTIAL_USERS.USER_NAME = NO_MAPPINGS.USER_NAME;
IF (POTENTIAL_USERS_TO_DELETE%ISOPEN)
THEN
CLOSE POTENTIAL_USERS_TO_DELETE;
END IF;
IF (USERS_WITHOUT_CHECKEDOUT_WORKFLOWS%ISOPEN)
THEN
CLOSE USERS_WITHOUT_CHECKEDOUT_WORKFLOWS;
END IF;
IF (USERS_WITHOUT_CHECKEDOUT_MAPPINGS%ISOPEN)
THEN
CLOSE USERS_WITHOUT_CHECKEDOUT_MAPPINGS;
END IF;
END LOOP;
END;
END;
这些是我不断收到的错误消息:
ORA-06550:第 22 行,第 29 列: PLS-00103:在预期以下情况之一时遇到符号“NO_WORKFLOWS”:
( 符号“(”被替换为“NO_WORKFLOWS”以继续。 ORA-06550:第 23 行,第 3 列: PLS-00103:在预期以下情况之一时遇到符号“THEN”:
) 和或作为 符号“)”被替换为“THEN”以继续。 ORA-06550:第 26 行,第 40 列: PLS-00103:在预期以下情况之一时遇到符号“NO_WORKFLOWS”:
( 符号“(”被替换为“NO_WORKFLOWS”以继续。 ORA-06550:第 27 行,第 44 列: PLS-00103:在预期以下情况之一时遇到符号“NO_MAPPINGS”:
(
【问题讨论】:
请编辑问题并显示如何定义 POTENTIAL_USERS、POTENTIAL_USERS_TO_DELETE、NO_WORKFLOWS 和 NO_MAPPINGS。我最初对此的看法是,您尝试像使用表格一样使用光标,这是不允许的,但我想了解更多信息,以便向您展示如何解决问题,而不仅仅是说“你不能那样做”。谢谢。 【参考方案1】:我意识到我这样做太难了。我所要做的就是将查询拆分为两个单独的删除脚本,然后单独运行每个脚本或作为脚本运行。
--Finds and deletes users with no access for past year
--and sees if they have any checked out workflows.
DELETE USER_NAME
FROM (SELECT USER_NAME
FROM GAI_PM.REP_USERS
WHERE USER_NAME NOT IN
(SELECT USER_NAME
FROM (SELECT ROW_NUMBER ()
OVER (
PARTITION BY REP_USERS.USER_NAME
ORDER BY
TO_DATE (
SUBSTR (
LAST_SAVED,
1,
10),
'MM/DD/YYYY') DESC)
RN,
REP_USERS.USER_NAME,
REP_VERSION_PROPS.LAST_SAVED
FROM GAI_PM.REP_USERS
JOIN
GAI_PM.REP_VERSION_PROPS
ON REP_USERS.USER_ID =
REP_VERSION_PROPS.USER_ID)
WHERE RN = 1
AND TO_DATE (SUBSTR (LAST_SAVED, 1, 10),
'MM/DD/YYYY') >
ADD_MONTHS (TRUNC (SYSDATE), -12))
AND UPPER (REP_USERS.USER_NAME) NOT LIKE '%ADMIN%'
AND UPPER (REP_USERS.USER_NAME) NOT LIKE '%CSTEINKAMP%')
WHERE USER_NAME IN
(WITH POTENTIAL_USERS_TO_DELETE
AS (SELECT USER_NAME, USER_ID
FROM GAI_PM.REP_USERS
WHERE USER_NAME NOT IN
(SELECT USER_NAME
FROM (SELECT ROW_NUMBER ()
OVER (
PARTITION BY REP_USERS.USER_NAME
ORDER BY
TO_DATE (
SUBSTR (
LAST_SAVED,
1,
10),
'MM/DD/YYYY') DESC)
RN,
REP_USERS.USER_NAME,
REP_VERSION_PROPS.LAST_SAVED
FROM GAI_PM.REP_USERS
JOIN
GAI_PM.REP_VERSION_PROPS
ON REP_USERS.USER_ID =
REP_VERSION_PROPS.USER_ID)
WHERE RN = 1
AND TO_DATE (
SUBSTR (LAST_SAVED, 1, 10),
'MM/DD/YYYY') >
ADD_MONTHS (TRUNC (SYSDATE),
-12))
AND UPPER (REP_USERS.USER_NAME) NOT LIKE '%ADMIN%'
AND UPPER (REP_USERS.USER_NAME) NOT LIKE
'%CSTEINKAMP%'),
CHECKED_OUT_WORKFLOWS
AS (SELECT C.SUBJ_NAME,
A.TASK_NAME,
B.USER_NAME,
USER_ID
FROM GAI_PM.OPB_TASK A
JOIN GAI_PM.OPB_USERS B
ON A.CHECKOUT_USER_ID = B.USER_ID
JOIN GAI_PM.OPB_SUBJECT C
ON A.SUBJECT_ID = C.SUBJ_ID
WHERE A.CHECKOUT_USER_ID <> 0)
SELECT DISTINCT POTENTIAL_USERS_TO_DELETE.USER_NAME
FROM POTENTIAL_USERS_TO_DELETE
LEFT JOIN
CHECKED_OUT_WORKFLOWS
ON POTENTIAL_USERS_TO_DELETE.USER_ID =
CHECKED_OUT_WORKFLOWS.USER_ID
WHERE CHECKED_OUT_WORKFLOWS.USER_NAME IS NULL);
--Finds and deletes users with no access for past year
--and sees if they have any checked out mappings.
DELETE USER_NAME
FROM (SELECT USER_NAME
FROM GAI_PM.REP_USERS
WHERE USER_NAME NOT IN
(SELECT USER_NAME
FROM (SELECT ROW_NUMBER ()
OVER (
PARTITION BY REP_USERS.USER_NAME
ORDER BY
TO_DATE (
SUBSTR (
LAST_SAVED,
1,
10),
'MM/DD/YYYY') DESC)
RN,
REP_USERS.USER_NAME,
REP_VERSION_PROPS.LAST_SAVED
FROM GAI_PM.REP_USERS
JOIN
GAI_PM.REP_VERSION_PROPS
ON REP_USERS.USER_ID =
REP_VERSION_PROPS.USER_ID)
WHERE RN = 1
AND TO_DATE (SUBSTR (LAST_SAVED, 1, 10),
'MM/DD/YYYY') >
ADD_MONTHS (TRUNC (SYSDATE), -12))
AND UPPER (REP_USERS.USER_NAME) NOT LIKE '%ADMIN%'
AND UPPER (REP_USERS.USER_NAME) NOT LIKE '%CSTEINKAMP%')
WHERE USER_NAME IN
(WITH POTENTIAL_USERS_TO_DELETE
AS (SELECT USER_NAME, USER_ID
FROM GAI_PM.REP_USERS
WHERE USER_NAME NOT IN
(SELECT USER_NAME
FROM (SELECT ROW_NUMBER ()
OVER (
PARTITION BY REP_USERS.USER_NAME
ORDER BY
TO_DATE (
SUBSTR (
LAST_SAVED,
1,
10),
'MM/DD/YYYY') DESC)
RN,
REP_USERS.USER_NAME,
REP_VERSION_PROPS.LAST_SAVED
FROM GAI_PM.REP_USERS
JOIN
GAI_PM.REP_VERSION_PROPS
ON REP_USERS.USER_ID =
REP_VERSION_PROPS.USER_ID)
WHERE RN = 1
AND TO_DATE (
SUBSTR (LAST_SAVED, 1, 10),
'MM/DD/YYYY') >
ADD_MONTHS (TRUNC (SYSDATE),
-12))
AND UPPER (REP_USERS.USER_NAME) NOT LIKE '%ADMIN%'
AND UPPER (REP_USERS.USER_NAME) NOT LIKE
'%CSTEINKAMP%'),
CHECKED_OUT_MAPPINGS
AS (SELECT C.SUBJ_NAME,
A.MAPPING_NAME,
B.USER_NAME,
B.USER_ID
FROM GAI_PM.OPB_MAPPING A
JOIN GAI_PM.OPB_USERS B
ON A.CHECKOUT_USER_ID = B.USER_ID
JOIN GAI_PM.OPB_SUBJECT C
ON A.SUBJECT_ID = C.SUBJ_ID
WHERE A.CHECKOUT_USER_ID <> 0)
SELECT DISTINCT POTENTIAL_USERS_TO_DELETE.USER_NAME
FROM POTENTIAL_USERS_TO_DELETE
LEFT JOIN
CHECKED_OUT_MAPPINGS
ON POTENTIAL_USERS_TO_DELETE.USER_ID =
CHECKED_OUT_MAPPINGS.USER_ID
WHERE CHECKED_OUT_MAPPINGS.USER_NAME IS NULL);
【讨论】:
以上是关于在其他两个游标中找到游标时如何从表中删除的主要内容,如果未能解决你的问题,请参考以下文章
如何从 PLSQL Oracle 过程中删除数据或清空游标?