尝试执行 FOREACH 时出现语法错误

Syntax error when trying to perform FOREACH

我有以下功能:

begin;
CREATE OR REPLACE FUNCTION convert_categories_16_12_2019() RETURNS VOID AS $$
DECLARE
    category_index VARCHAR;
    has_extra1_content  BOOLEAN;
    has_extra2_content BOOLEAN;
    result_category BOOLEAN;
    r RECORD;
BEGIN
    FOR r IN (SELECT * FROM campaign_campaign) LOOP
        result_category = FALSE;
        has_extra1_content  = FALSE;
        has_extra2_content = FALSE;

        FOREACH category_index IN ARRAY regexp_split_to_array(r.category, ',') LOOP

            IF (category_index::int = 6 OR
                category_index::int = 7) 
            THEN has_extra1_content = TRUE 
            END IF;

            IF (category_index::int = 0 OR 
                category_index::int = 1 OR
                category_index::int = 2 OR
                category_index::int = 3 OR
                category_index::int = 4 OR                          
                category_index::int = 5)                            
            THEN has_extra2_content = TRUE 
            END IF;

            CASE
                WHEN has_extra1_content  AND NOT has_extra2_content
                THEN result_category = 0;

                WHEN has_extra2_content AND has_extra1_content 
                THEN result_category = 1;
            ELSE
                result_category = 2;
            END CASE;

        END LOOP;

        UPDATE campaign_campaign 
        SET campaign_campaign.category = result_category
        WHERE id = r.id;

    END LOOP;
    RETURN;
END
$$ LANGUAGE plpgsql;

select convert_categories_16_12_2019();
DROP FUNCTION convert_categories_16_12_2019;
rollback;

但是当我尝试 运行 时,我得到:

ERROR:  ERROR:  syntax error(near: "END")
LINE 21:             END IF;

有人可以解释为什么会出现这个错误吗?我没有看到任何语法问题。

我使用的资源:
https://dba.stackexchange.com/questions/234657/syntax-error-when-using-exception-inside-for-loop
https://www.postgresql.org/docs/9.4/plpgsql-control-structures.html

问题是 THEN 分支中缺少 ; after 语句,因此应该是:

IF (category_index::int = 6 OR
    category_index::int = 7) 
THEN has_extra1_content = TRUE; /* semicolon here too! */
END IF;

亲爱的 Whosebug 用户,我已经用这个 UPDATE 语句替换了函数:

UPDATE campaign_campaign SET category =

    CASE WHEN (
        campaign_campaign.category != '' 
        AND regexp_split_to_array(campaign_campaign.category, ',')::int[] && ARRAY[6,7] 
        AND NOT regexp_split_to_array(campaign_campaign.category, ',')::int[] && ARRAY[0,1,2,3,4,5]
    ) THEN 0

    WHEN (
        campaign_campaign.category != ''
        AND regexp_split_to_array(campaign_campaign.category, ',')::int[] && ARRAY[0,1,2,3,4,5]
        AND NOT regexp_split_to_array(campaign_campaign.category, ',')::int[] && ARRAY[6,7]
    ) THEN 1

    ELSE 2

    END;

看起来你可以将所有内容替换为:

UPDATE campaign_campaign 
SET    category = 
   CASE WHEN string_to_array(category, ',') && '{6,7}'::text[] THEN
      CASE WHEN string_to_array(category, ',') && '{0,1,2,3,4,5}'::text[] THEN '1' ELSE '0' END
   ELSE '2' END;

这假定您的原始文本字符串中没有无关紧要的空格。否则,仍然需要强制转换为 int[](就像您所做的那样)。

UPDATE 语句中的目标列不能是 table 限定的,顺便说一句,所以不是 SET campaign_campaign.category = ....

然后您应该将列 category 转换为 integer
或者在 boolean 列中使用 true / false / null