在其他两个游标中找到游标时如何从表中删除

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 过程中删除数据或清空游标?

请教大虾们,反复执行同一个游标(cursor),每次从表中取出1000条,直到将表中的数据取完;

PL/SQL - 声明带有由其他游标填充的表的游标时出错

如何从表中删除作为其他两个表相交结果的元素