簡體   English   中英

錯誤 cursor 在 PL/pgSQL 中的第一個循環后不存在

[英]ERROR cursor does not exist after first loop in PL/pgSQL

我需要將大量 csv 文件加載到 PostgreSQL 數據庫中。 我有一個表source_files ,其中包含文件路徑和一個標志,該標志指示是否已經為我需要加載的所有 csv 文件加載了文件。

我編寫了以下代碼,它正確加載了第一個文件,但隨后引發了錯誤:

ERROR: cursor "curs" does not exist

為什么我會收到此錯誤,我該如何解決?

DO $$
DECLARE
    file_record record;
    curs CURSOR
        FOR SELECT id, file_path
            FROM source_files
            WHERE added_to_db=FALSE
            ORDER BY id;
BEGIN
    OPEN curs;
    LOOP
        -- Get next entry in source file which contains name of csv to load
        FETCH curs INTO file_record;
        exit WHEN NOT found;
        BEGIN
            -- As we need to add a column to the data after loading csv but before inserting
            -- into final table we use a temporary table mytemp
            DROP TABLE mytemp;

            CREATE TABLE mytemp
            (
                dataA numeric,
                dataB numeric
            );

            -- Load csv file   
            EXECUTE FORMAT('COPY mytemp
                            FROM ''%s''
                            DELIMITER '',''
                            CSV HEADER;', file_record.file_path);

            -- Add Column specifying what source file the data is from
            ALTER TABLE mytemp
                ADD COLUMN source_id int;

            UPDATE mytemp 
                SET source_id=file_record.id;

            -- Add the data to the destination table
            INSERT INTO data_table(
                dataA,
                dataB,
                source_id
            )
            SELECT 
                mytemp.dataA,
                mytemp.dataB
                mytemp.source_id
            FROM 
                mytemp

            -- Set a flag to indicate that the current file in source_files has been loaded
            UPDATE source_files
                SET added_to_db=TRUE WHERE CURRENT OF curs;

            COMMIT;
        END;

    END LOOP;
    CLOSE curs;

END $$;

您的代碼有一個大問題是COMMIT 可以DO語句中使用COMMIT ,但 cursor 會在事務結束后立即關閉。 在 SQL 中,您可以創建一個 cursor WITH HOLD ,它在事務結束后仍然有效,但在 PL/pgSQL 中不可用。

我建議刪除COMMIT

代碼中的另一個錯誤是您使用了 function format ,這會使您面臨 SQL 注入。 代替

FORMAT('COPY mytemp
        FROM ''%s''
        DELIMITER '',''
        CSV HEADER;', file_record.file_path);

利用

FORMAT('COPY mytemp
        FROM %L
        DELIMITER '',''
        CSV HEADER;', file_record.file_path);

您可以通過在循環中使用隱式 cursor 來簡化代碼:

FOR file_record IN
   SELECT id, file_path
   FROM source_files
   WHERE added_to_db=FALSE
   ORDER BY id
LOOP
   ...
END LOOP;

這樣可以節省您聲明 cursor 和EXIT WHEN的時間。 無論如何, OPENCLOSE語句都是不必要的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM