使用时间和日期通过别名比较无效对象表?

问题描述 投票:0回答:1

我最近发布了一个使用 DBLinks 和监视无效对象的问题。现在我必须制作一个表并按日期注册所有无效对象,并在该代码的运行之间进行比较,如果有任何更改(对象更改其状态,有新对象等),代码将打印更改,例如这个:

DBLink 1:
(changes found)


DBLink 2:
No changes
.
.
.

Consecutively

为此我创建了一个表

CREATE TABLE Invalid_Objects (
    id NUMBER PRIMARY KEY,
    alias VARCHAR2(30),
    user_db_links VARCHAR2(128),
    owner VARCHAR2(128),
    object_name VARCHAR2(128),
    status VARCHAR2(30),
    object_type VARCHAR2(64),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_checked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

我使用的代码是:

-- We enable server output in the SQL client.
SET SERVEROUTPUT ON

DECLARE
    CURSOR cur_previous_results IS
        SELECT owner, object_name, status, object_type
        FROM Invalid_Objects
        WHERE alias = (SELECT MAX(alias) FROM Invalid_Objects);

    TYPE obj_details_type IS RECORD (
      owner         VARCHAR2(128),
      object_name   VARCHAR2(128),
      status        VARCHAR2(30),
      object_type   VARCHAR2(64)
    );

    TYPE obj_details_table IS TABLE OF obj_details_type;

    obj_details_list obj_details_table := obj_details_table();
    v_db_link_name VARCHAR2(128);
    v_row_count NUMBER := 0;
    v_current_alias VARCHAR2(30);
    v_previous_alias VARCHAR2(30);
    v_object_found NUMBER; -- Variable to store the search state of the object
BEGIN
    v_current_alias := TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS');
    SELECT MAX(alias) INTO v_previous_alias FROM Invalid_Objects;

    FOR rec_link IN (SELECT db_link FROM user_db_links) LOOP
        v_db_link_name := rec_link.db_link;
        BEGIN
            EXECUTE IMMEDIATE 'SELECT owner, object_name, status, object_type
                               FROM dba_objects@'||rec_link.db_link||'
                              WHERE status = ''INVALID'''
                            BULK COLLECT INTO obj_details_list;

            FOR i IN 1 .. obj_details_list.COUNT LOOP
                v_row_count := v_row_count + 1;
                INSERT INTO Invalid_Objects (id, alias, user_db_links, owner, object_name, status, object_type)
                VALUES (v_row_count, v_current_alias, v_db_link_name, obj_details_list(i).owner, obj_details_list(i).object_name, obj_details_list(i).status, obj_details_list(i).object_type);
            END LOOP;

            IF v_previous_alias IS NOT NULL THEN
                dbms_output.put_line('Comparing with previous run (alias: ' || v_previous_alias || '):');

                FOR rec_current IN (SELECT owner, object_name, status, object_type FROM Invalid_Objects WHERE alias = v_current_alias) LOOP
                    -- We initialize v_object_found to 0 (false)
                    v_object_found := 0;

                    -- We move the cursor cur_previous_results to find the current object
                    FOR rec_previous IN cur_previous_results LOOP
                        IF rec_previous.owner = rec_current.owner AND rec_previous.object_name = rec_current.object_name THEN
                            -- If we find the current object in the results above, we set v_object_found to 1 (true)
                            v_object_found := 1;
                            EXIT;
                        END IF;
                    END LOOP;

                    -- If v_object_found is 0, the current object was not found in the previous results and is considered new
                    IF v_object_found = 0 THEN
                        dbms_output.put_line('New object: ' || rec_current.object_name);
                    END IF;
                END LOOP;
            ELSE
                dbms_output.put_line('There is no previous run to compare.');
            END IF;
            
            -- Close database link inside FOR loop
            dbms_session.close_database_link(v_db_link_name);
        EXCEPTION
            WHEN OTHERS THEN
                dbms_output.put_line('Error running dynamic query for link ' || v_db_link_name || ': ' || SQLERRM);
                dbms_session.close_database_link(v_db_link_name); -- we close the link in case of error
        END;
    END LOOP;

    -- Commit after closing all links
    COMMIT;
EXCEPTION
    WHEN OTHERS THEN -- We do not allow a mistake to break the cycle, it continues
        dbms_output.put_line(v_db_link_name || ' errored: ' || SQLERRM);
END;
/

但它只打印这个错误:

There is no previous run to compare.
Error executing dynamic query for DBLINK link:
ORA-02080: database link is in use
DBLINK errored: ORA-02080: database link is in
use

PL/SQL procedure completed successfully.

我的推理正确吗,还是有其他方法可以关闭 DBLinks?

oracle object alias sqlplus dblink
1个回答
0
投票

在尝试关闭会话在当前事务中使用的链接之前,您需要发出

COMMIT
,即使它只是一个
SELECT
语句。然后它会让你关闭链接。

        COMMIT; -- add here
        dbms_session.close_database_link(v_db_link_name);
    EXCEPTION
        WHEN OTHERS THEN
            dbms_output.put_line('Error running dynamic query for link ' || v_db_link_name || ': ' || SQLERRM);
            COMMIT; -- and here
            dbms_session.close_database_link(v_db_link_name); -- we close the link in case of error
    END;
© www.soinside.com 2019 - 2024. All rights reserved.