PLPGSQL函数中的INSERT错误

时间:2012-02-28 14:01:28

标签: sql postgresql plpgsql

您好我在尝试了以下解决方案之后,一直在研究此代码:     Dynamic column names in view (Postgres)

我遇到了一些我似乎无法解决的错误,我已经解决了很多问题,但我无法解决这个问题,请记住我对此很新:)

这是我收到的错误:

ERROR:  missing FROM-clause entry for table "r"
LINE 2:    VALUES (r.country_name, r."Feb-2011", r."Mar-2011", r."Ap...
               ^
QUERY:  INSERT INTO "avg_enroll_rate" (country, "Feb-2011", "Mar-2011", "Apr-2011", "May-2011", "Jun-2011", "Jul-2011", "Aug-2011", "Sep-2011", "Oct-2011", "Nov-2011", "Dec-2011", "Jan-2012")
                    VALUES (r.country_name, r."Feb-2011", r."Mar-2011", r."Apr-2011", r."May-2011", r."Jun-2011",
                    r."Jul-2011", r."Aug-2011", r."Sep-2011", r."Oct-2011", r."Nov-2011",
                    r."Dec-2011", r."Jan-2012")
CONTEXT:  PL/pgSQL function "test" line 83 at EXECUTE statement

这是我的代码:

DROP FUNCTION public.test();
create or replace function public.test()
RETURNS void
SECURITY DEFINER
AS $proc$
DECLARE
    month1 text;
    month2 text;
    month3 text;
    month4 text;
    month5 text;
    month6 text;
    month7 text;
    month8 text;
    month9 text;
    month10 text;
    month11 text;
    month12 text;

    sqlStr text;
    sqlStr2 text;
    insertStr text;
    r record;

BEGIN 
    select to_char((current_date - interval '1 Month')::date,'Mon-YYYY') INTO month1;
    select to_char((current_date - interval '2 Month')::date,'Mon-YYYY') INTO month2;
    select to_char((current_date - interval '3 Month')::date,'Mon-YYYY') INTO month3;
    select to_char((current_date - interval '4 Month')::date,'Mon-YYYY') INTO month4;
    select to_char((current_date - interval '5 Month')::date,'Mon-YYYY') INTO month5;
    select to_char((current_date - interval '6 Month')::date,'Mon-YYYY') INTO month6;
    select to_char((current_date - interval '7 Month')::date,'Mon-YYYY') INTO month7;
    select to_char((current_date - interval '8 Month')::date,'Mon-YYYY') INTO month8;
    select to_char((current_date - interval '9 Month')::date,'Mon-YYYY') INTO month9;
    select to_char((current_date - interval '10 Month')::date,'Mon-YYYY') INTO month10;
    select to_char((current_date - interval '11 Month')::date,'Mon-YYYY') INTO month11;
    select to_char((current_date - interval '12 Month')::date,'Mon-YYYY') INTO month12;

    --RAISE NOTICE 'Month1: %', month1;
    --RAISE NOTICE 'Month2: %', month2;

    sqlStr := $$SELECT c.country_name,  
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '12 months' THEN 1 ELSE 0 END ) AS "$$ || month12 || $$",
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '11 months' THEN 1 ELSE 0 END ) AS "$$ || month11 || $$",
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '10 months' THEN 1 ELSE 0 END ) AS "$$ || month10 || $$",
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '9 months' THEN 1 ELSE 0 END ) AS "$$ || month9 || $$",
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '8 months' THEN 1 ELSE 0 END ) AS "$$ || month8 || $$",
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '7 months' THEN 1 ELSE 0 END ) AS "$$ || month7 || $$",
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '6 months' THEN 1 ELSE 0 END ) AS "$$ || month6 || $$",
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '5 months' THEN 1 ELSE 0 END ) AS "$$ || month5 || $$",
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '4 months' THEN 1 ELSE 0 END ) AS "$$ || month4 || $$",
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '3 months' THEN 1 ELSE 0 END ) AS "$$ || month3 || $$",
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '2 months' THEN 1 ELSE 0 END ) AS "$$ || month2 || $$",
                SUM( CASE WHEN date_trunc('month', "C1".eldate::date) =  date_trunc('month', now()) - interval '1 months' THEN 1 ELSE 0 END ) AS "$$ || month1 || $$"

            FROM country AS c
                INNER JOIN "site" AS s using (country_id)
                INNER JOIN "subject_C1" AS "C1" ON "s"."site_id" = "C1"."site_id"

            GROUP BY 1$$;

    EXECUTE $$DROP TABLE avg_enroll_rate$$;
    EXECUTE $$CREATE TABLE avg_enroll_rate (country VARCHAR(512), "$$ || month12 || $$" bigint, "$$ || month11 || $$" bigint, "$$ 
    || month10 || $$" bigint, "$$ || month9 || $$" bigint, "$$ || month8 || $$" bigint, "$$ || month7 || $$" bigint, "$$ || month6 || $$" bigint, "$$ 
    || month5 || $$" bigint, "$$ || month4 || $$" bigint, "$$ || month3 || $$" bigint, "$$ || month2 || $$" bigint, "$$ || month1 || $$" bigint)$$; 


    FOR r IN
        EXECUTE sqlStr
    LOOP
        RAISE NOTICE 'Record 1: %', r;

        sqlStr2 := $$INSERT INTO "avg_enroll_rate" (country, "$$ || month12 || $$", "$$ || month11  || $$", "$$ ||  month10  || $$", "$$ ||  month9  || $$", "$$ ||  month8  || $$", "$$ ||  month7  || $$", "$$ ||  month6  || $$", "$$ ||  month5  || $$", "$$ ||  month4  || $$", "$$ ||  month3  || $$", "$$ ||  month2  || $$", "$$ ||  month1 || $$")
        VALUES ("r".country_name, r."$$ || month12 || $$", r."$$ || month11 || $$", r."$$ || month10 || $$", r."$$ || month9 || $$", r."$$ || month8 || $$",
        r."$$ || month7 || $$", r."$$ || month6 || $$", r."$$ || month5 || $$", r."$$ || month4 || $$", r."$$ || month3 || $$",
        r."$$ || month2 || $$", r."$$ || month1 || $$")$$;


        RAISE NOTICE 'SQL = [%]', sqlStr2;

        EXECUTE sqlStr2; 

    END LOOP;


END
$proc$
LANGUAGE 'PLPGSQL';

1 个答案:

答案 0 :(得分:1)

您在plpgsql中遇到执行动态SQL的限制。 I quote the manual

  

在计算命令上没有替换PL / pgSQL变量   串。必须在命令中插入任何必需的变量值   字符串,因为它被构造;或者您可以使用所述的参数   下方。

因此,您已将值作为文本文字放入SQL字符串中(注意SQL注入!使用quote_literal()),或者您可以使用USING子句 - 在大多数情况下这是优先的。您可以在same spot in the manual找到更多相关信息。