用游标进行plpgSQL函数查询

时间:2015-11-30 20:35:02

标签: sql postgresql cursor plpgsql

作为一名真正的学生,我在昨晚的课程中工作:) 但我试着写了几天这个查询,我不知道该怎么做。这就是为什么我在这里写作的原因。

很抱歉这可能是一个愚蠢的问题,但是我们所有人都在前一段时间里做了很多错误和问题的编程。 (抱歉我的英语,它现在很完美)。

顺便说一下,我的任务是:

我们有3个表格(地区,城市和实验[名为'数据'])。第三个表格(实验['数据'])有so2_d字段(特定日期在空中的内容为so2)。

我需要创建一份报告,了解每个城市空气中最大的内容分布情况,使用特定年份的季度(确切地说并不重要)。 即,该表必须如下所示:

table

这意味着我们需要通过水平和垂直方式来总结。

我尝试用1个光标,2个光标做它...它没有用。在大多数情况下,我遇到了这个错误:so2是不明确的。

这是我的代码示例。 (我知道它很糟糕但没有结束,但我希望你能理解......):

    CREATE OR REPLACE FUNCTION so2_report()
    RETURNS text AS
    $$
    DECLARE
    name_r regions.name_r %TYPE; name_c cities.name_c %TYPE; 
    quarter_1 data.so2_d %TYPE := 0; quarter_2 data.so2_d %TYPE := 0; quarter_3 data.so2_d %TYPE := 0; quarter_4 data.so2_d %TYPE := 0;
    quarter INTEGER; counter INTEGER := 0;
    string TEXT;

    cursor1 CURSOR FOR 
    SELECT regions.name_r, cities.name_c FROM regions INNER JOIN cities USING (id_r) INNER JOIN data USING (id_c);

    cursor2 CURSOR FOR
    SELECT max(data.so2_d) FROM data WHERE EXTRACT(QUARTER FROM date_d) = quarter AND data.id_c = counter;

    BEGIN

    string := repeat(' ', 90) || 'Report' || E'\n';
    string := string || repeat(' ', 65) || 'about maximum so2 content in air' || E'\n\n';

    string := string || repeat(' ', 5) || 'Region' || repeat(' ', 15) || 'City' || repeat(' ', 25) || 'I quarter' || repeat(' ', 10) ||
    'ІІ quarter' || repeat(' ', 10) || 'ІІІ quarter' || repeat(' ', 10) || 'IV quarter' || repeat(' ', 10) || 'All Year' || E'\n\n';

    OPEN cursor1;
    LOOP

    FETCH next FROM cursor1 INTO name_r, name_c;
    exit when not found;
    string := string || rpad(name_r, 25) || rpad(name_c, 25);

    OPEN cursor2;
    counter := counter + 1; 
    quarter := 0;
    LOOP
    quarter := quarter + 1;

    FETCH next FROM cursor2 INTO quarter_1, quarter_2, quarter_3, quarter_4;
    exit when not found;
    string := string || rpad(TO_CHAR(quarter_1, '999.99'), 20) || 
    rpad(TO_CHAR(quarter_2, '999.99'), 20) || rpad(TO_CHAR(quarter_3, '999.99'), 20) || rpad(TO_CHAR(quarter_4, '999.99'), 20) || E'\n';

    END LOOP;
    CLOSE cursor2;

    END LOOP;
    CLOSE cursor1;


    RETURN string;
    END
    $$
    LANGUAGE 'plpgsql';
    SELECT so2_report();



I will be grateful for any help. 

GUYS,我已经解决了!在这里你得到了代码:

    CREATE OR REPLACE FUNCTION s_report()
RETURNS text AS
$$
DECLARE
name_r regions.name_r %TYPE; name_c cities.name_c %TYPE;
quarter_1 data.so2_d %TYPE; quarter_2 data.so2_d %TYPE; quarter_3 data.so2_d %TYPE; quarter_4 data.so2_d %TYPE;
year REAL; sum REAL ARRAY[5];
string TEXT;

cursor1 CURSOR FOR
SELECT regions.name_r, cities.name_c,
                max( CASE WHEN EXTRACT(QUARTER FROM date_d) = 1 AND EXTRACT(YEAR FROM date_d) = EXTRACT(YEAR FROM current_date) THEN so2_d ELSE 0 END ) As Quarter_1,
        max( CASE WHEN EXTRACT(QUARTER FROM date_d) = 2 AND EXTRACT(YEAR FROM date_d) = EXTRACT(YEAR FROM current_date) THEN so2_d ELSE 0 END ) As Quarter_2,
        max( CASE WHEN EXTRACT(QUARTER FROM date_d) = 3 AND EXTRACT(YEAR FROM date_d) = EXTRACT(YEAR FROM current_date) THEN so2_d ELSE 0 END ) As Quarter_3,
        max( CASE WHEN EXTRACT(QUARTER FROM date_d) = 4 AND EXTRACT(YEAR FROM date_d) = EXTRACT(YEAR FROM current_date) THEN so2_d ELSE 0 END ) As Quarter_4
        FROM regions INNER JOIN cities USING (id_r) INNER JOIN data USING (id_c) GROUP BY regions.name_r, cities.name_c;


BEGIN
-- формуємо назву звіту
string := repeat(' ', 50) || 'Звіт' || E'\n';
string := string || repeat(' ', 27) || 'про розподіл максимальних значень SO2 в повітрі' || E'\n\n';
-- формуємо рядок заголовку звіту
string := string || repeat(' ', 5) || 'Область' || repeat(' ', 15) || 'Місто' || repeat(' ', 10) || 'I квартал' || repeat(' ', 5) ||
'ІІ квартал' || repeat(' ', 5) || 'ІІІ квартал' || repeat(' ', 5) || 'IV квартал' || repeat(' ', 5) || 'Рік' || E'\n\n';
--вперед
sum[1] := 0; sum[2] := 0; sum[3] := 0; sum[4] := 0; sum[5] := 0;
--відкриваємо курсор
OPEN cursor1;
LOOP
 --витягаємо значення з курсору
FETCH next FROM cursor1 INTO name_r, name_c, quarter_1, quarter_2, quarter_3, quarter_4;
exit when not found;
year := 0;
year := quarter_1 + quarter_2 + quarter_3 + quarter_4;
sum[1] := sum[1] + quarter_1;
sum[2] := sum[2] + quarter_2;
sum[3] := sum[3] + quarter_3;
sum[4] := sum[4] + quarter_4;
sum[5] := sum[5] + year;


string := string || rpad(name_r, 25) || rpad(name_c, 16) || rpad(TO_CHAR(quarter_1, '999.99'), 16) || rpad(TO_CHAR(quarter_2, '999.99'), 14) ||
rpad(TO_CHAR(quarter_3, '999.99'), 15) || rpad(TO_CHAR(quarter_4, '999.99'), 12) || TO_CHAR(year, '999.99') || E'\n';

END LOOP;
CLOSE cursor1;
string := string || E'\n' || repeat(' ', 11) || rpad('Всього', 30) ||  rpad(TO_CHAR(sum[1], '999.99'), 16) || rpad(TO_CHAR(sum[2], '999.99'), 14) ||
rpad(TO_CHAR(sum[3], '999.99'), 15) || rpad(TO_CHAR(sum[4], '999.99'), 12) || TO_CHAR(sum[5], '999.99');

RETURN string;
END
$$
LANGUAGE 'plpgsql';
SELECT s_report();

1 个答案:

答案 0 :(得分:0)

尽量避免使用程序代码。
您正在使用SQL - 最美丽的声明性语言之一。

如果我从您的代码中正确地猜测您的要求和表格结构,下面的简单SQL语句应该会给您一个非常接近您要求的结果:

SELECT regions.name_r, cities.name_c, 
       avg( CASE WHEN EXTRACT(QUARTER FROM date_d) = 1 THEN so2_d END ) As Quarter_1,
       avg( CASE WHEN EXTRACT(QUARTER FROM date_d) = 2 THEN so2_d END ) As Quarter_2,
       avg( CASE WHEN EXTRACT(QUARTER FROM date_d) = 3 THEN so2_d END ) As Quarter_3,
       avg( CASE WHEN EXTRACT(QUARTER FROM date_d) = 4 THEN so2_d END ) As Quarter_4
FROM regions 
INNER JOIN cities USING (id_r)
INNER JOIN data USING (id_c) 
GROUP BY regions.name_r, cities.name_c
; 

缺失的部分是每个季度的最终总和,以及每年的总和和最终总数
这个查询应该很容易实现(未经测试):

WITH dd As(
    SELECT regions.name_r, cities.name_c, 
           avg( CASE WHEN EXTRACT(QUARTER FROM date_d) = 1 THEN so2_d END ) As Quarter_1,
           avg( CASE WHEN EXTRACT(QUARTER FROM date_d) = 2 THEN so2_d END ) As Quarter_2,
           avg( CASE WHEN EXTRACT(QUARTER FROM date_d) = 3 THEN so2_d END ) As Quarter_3,
           avg( CASE WHEN EXTRACT(QUARTER FROM date_d) = 4 THEN so2_d END ) As Quarter_4
    FROM regions 
    INNER JOIN cities USING (id_r)
    INNER JOIN data USING (id_c) 
    GROUP BY regions.name_r, cities.name_c
)
SELECT dd.*,
       Quarter_1 + Quarter_2 + Quarter_3 + Quarter_4 As All_year
FROM dd
UNION All
SELECT 'TOTAL', NULL,
       SUM( Quarter_1 ),
       SUM( Quarter_2 ),
       SUM( Quarter_3 ),
       SUM( Quarter_4 ),
       SUM( Quarter_1 + Quarter_2 + Quarter_3 + Quarter_4 )
FROM dd
;