如何在PLPGSQL中将WITH与FOR循环结合使用?

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

我想创建一个存储函数,其主体将遍历WITH语句的结果。那可能吗?到目前为止,我在FOR上收到WITH后面的语法错误。最小示例:

DO $$
DECLARE loop_col1 RECORD;
BEGIN 
    WITH temp_table AS (
        SELECT col1, col2 FROM files
    )
    FOR loop_col1 IN
        SELECT DISTINCT col1 FROM temp_table
    LOOP
        -- do something
        raise notice 'loop_uurid %', loop_col1
    END LOOP;
END $$;

我想要遍历col1的原因是它对col2的值进行分组,并且对于每组值我都希望在其他表中放置新关系(例如,“做某事”部分)

其他可以让我拥有“临时表”数据的解决方案也很好。

完整的上下文查询:

CREATE OR REPLACE FUNCTION enqueue_postprocessing_jobs()
RETURNS void
LANGUAGE plpgsql AS $$
DECLARE
    loop_group_uufid RECORD;
    loop_uurid RECORD;
BEGIN
    -- 1. Find information of files that might be usable for new postprocessing
    -- job. Query results in all files that are related to postprocessing jobs
    WITH candidate_postprocessing_files
    SELECT uufid, uurid, source, group_uufid
    FROM files
    WHERE source='CRACKS' OR source='BACKGROUND'
    AND uufid NOT IN (
        -- Find all files which have do have a job associated with them
        SELECT DISTINCT uufid FROM get_files_and_jobs()
        WHERE type='POSTPROCESSING'
    );

    -- 2. Group candidate files by group_uufid (a) and loop over them to see if
    -- all necessary files are present (b), insert new job if so (c) and
    -- connect job to files (d)
    FOR loop_group_uufid IN
        SELECT DISTINCT group_uufid
        FROM candidate_postprocessing_files
    LOOP
        -- a. Make reusable temp table with only the files of this group
        WITH group_postprocessing_files AS (
            SELECT * FROM candidate_postprocessing_files
            WHERE group_uufid=loop_group_uufid
        ),
        -- b. Select ids of those files and runs where all necessary files are
        -- present. Query results in a table is 0 rows long if not all files
        -- are present for this job, otherwise, it should be 2 rows long.
        -- One row for cracks, one row for background.
        -- In other words, this whole table function as a single job candidate.
        job_candidate AS (
            SELECT uufid, uurid FROM group_postprocessing_files
            WHERE 'CRACKS' IN (SELECT source FROM group_postprocessing_files)
            AND 'BACKGROUND' IN (SELECT source FROM group_postprocessing_files)
        )
        -- c&D. Insert those new jobs and connect files
        -- Should only loop once
        FOR loop_uurid IN
            SELECT DISTINCT uurid FROM job_candidate
        LOOP
            -- c. Insert jobs
            WITH job AS (
                -- TODO Support not_before and priority
                SELECT enqueue_job AS uujid
                FROM enqueue_job(uurid, '' , 'POSTPROCESSING')
            )
            -- d. Connect new jobs to files
            INSERT INTO files_to_jobs
            SELECT job_candidate.uufid, job.uujid
            FROM job;
        END LOOP;
    END LOOP;
END $$;

所以我的问题是:

  1. 如何与FOR选择结合使用FOR循环?
  2. 如果不可能,那么如何获取可以循环的临时表数据?
postgresql plpgsql
1个回答
0
投票

您可以将FOR循环与WITH子句结合使用,但是WITH子句必须属于SELECT语句(WITH子句不是独立的语句:]

DO
$$
DECLARE loop_col1 RECORD;
BEGIN 
    FOR loop_col1 IN
        WITH temp_table AS (
         SELECT col1, col2 FROM files
        )
        SELECT DISTINCT col1 FROM temp_table
    LOOP
        -- do something
        raise notice 'loop_uurid %', loop_col1;
    END LOOP;
END $$;

否则,您可以创建一个临时表:

DO $$
DECLARE loop_col1 RECORD;
BEGIN 

    CREATE TEMPORARY table temp_table ON COMMIT DROP AS
        SELECT col1, col2 FROM files;

    FOR loop_col1 IN
        SELECT DISTINCT col1 FROM temp_table
    LOOP
        -- do something
        raise notice 'loop_uurid %', loop_col1;
    END LOOP;

END $$;
© www.soinside.com 2019 - 2024. All rights reserved.