3

I'm trying to create a function that sums the result of all of one query's values and compares it to a number of another, simple query.

This is what I have, however I'm getting a syntax error near begin (2nd line):

CREATE FUNCTION trigf1(sbno integer, scid numeric(4,0)) RETURNS integer
BEGIN
    declare sum int default 0;
    declare max as SELECT totvoters FROM ballotbox WHERE cid=scid AND bno=sbno;

    for r as
        SELECT nofvotes FROM votes WHERE cid=scid AND bno=sbno;
    do
        set sum = sum + r.nofvotes;
    end for

    if sum > max
        then return(0);
    else
        return(1);
END

This results in:

Syntax error near 'BEGIN'

I'm using postgreSQL and the pgadminIII (just in case it is relevant).

I have no idea why I'm getting this error, everything seems to be exactly as the textbook defined. (This is the text book I'm using: http://digilib.usu.ac.id/buku/107859/Database-systems-concepts,-6th-ed.html)

3
  • What's the syntax error?
    – Marc
    Aug 2, 2015 at 16:07
  • 2
    RETURNS integer AS $$ Aug 2, 2015 at 16:10
  • 1
    Read the manual carefully: the function source code is a string literal and there is only a single declare section and you are missing the language option. And there is no set in PL/pgSQL. Assigments are done using := Aug 2, 2015 at 16:10

3 Answers 3

15

I don't know which "textbook" you were using but if everything you wrote is exactly as in that book, that book is totally wrong:

CREATE FUNCTION trigf1(sbno integer, scid numeric(4,0)) 
    RETURNS integer
AS         -- error #1: no AS keyword
$body$     -- error #2: use dollar quoting to specify the function body as a string
DECLARE    -- error #3: the declare block comes before the actual code
   sum_ integer := 0; -- error #5: you can't use a reserved keyword as a variable
   max_ integer;      -- error #6:  you can't initialize a variable with a select,
   r   record;   -- you need to declare the record for the cursor loop
BEGIN
   select totvoters
     into max_
   from ballotbox 
   WHERE cid=scid AND bno=sbno;

    -- error #7: the syntax for a loop uses IN not AS
    -- error #8: you need to declare R before you can use it
    -- error #9: the SELECT for a cursor loop must NOT be terminated with a ;
    FOR r IN SELECT nofvotes FROM votes WHERE cid=scid AND bno=sbno
    loop  -- error #10: you need to use LOOP, not DO

        sum_ := sum_ + r.nofvotes;  -- error #11: you need to use := for an assignment, not SET
    end loop; -- error #12: it's END LOOP
              -- error #13: you need to terminate the statement with a ;

    if sum_ > max_ then 
       return 0;
    else
       return 1;
    end if; -- error #14: an END if is required
END;
$body$
language plpgsql; -- error #14: you need to specify the language

The manual documents all this:


The whole FOR loop is not needed and extremely inefficient. It can be replaced with:

SELECT sum(nofvotes)
  into sum_
FROM votes 
WHERE cid=scid AND bno=sbno;

Postgres has a native boolean type, it's better to use that instead of integers. If you declare the function as returns boolean, the last line can be simplified to

return max_ > sum_;

This part:

 select totvoters
   into max_
 from ballotbox 
 WHERE cid=scid AND bno=sbno;

will only work if cid,bno is unique in the table ballotbox. Otherwise you might get an error at runtime if the select returns more than one row.


Assuming that the select on ballotbox does use the primary (or a unique) key, the whole function can be simplified to a small SQL expression:

create function trigf1(sbno integer, scid numeric(4,0))
  returns boolean
as
$body$
  return (select totvoters from ballotbox WHERE cid=scid AND bno=sbno) > 
         (SELECT sum(nofvotes) FROM votes WHERE cid=scid AND bno=sbno);
$body$
language sql;
7
  • 2
    Can't explain more +1 awesome Aug 2, 2015 at 16:33
  • Very strange (about the text book). It says absolutley nothing about putting as after returns, and mentions that declares should be on the inside. This is the book I'm using: digilib.usu.ac.id/buku/107859/…
    – Tom Klino
    Aug 2, 2015 at 16:51
  • @TomKlino So which "text book" is that? It's most definitely not the official manual Aug 2, 2015 at 16:52
  • This is the book I got from the university. It is pretty official, and that's why I'm so confused. It shouldn't have errors, and espacially not that many
    – Tom Klino
    Aug 2, 2015 at 16:55
  • 1
    @TomKlino: then they gave you the wrong one. Or they gave you one for a different DBMS - are you sure that book is for Postgres? The description on Amazon sounds more like it is a general DBMS book, rather than one specific for Postgres. Aug 2, 2015 at 16:57
0

I am not really a postgresSQL person, but I would have thought

declare max as SELECT totvoters FROM ballotbox WHERE cid=scid AND bno=sbno;

should be

declare max := SELECT totvoters FROM ballotbox WHERE cid=scid AND bno=sbno;
0
0

The body of the function should be a string after the as keyword, i.e. as 'code...'. Usually a dollar-quoted string is used:

CREATE FUNCTION trigf1(sbno integer, scid numeric(4,0)) RETURNS integer
AS $$
BEGIN
    declare sum int default 0;
    declare max as SELECT totvoters FROM ballotbox WHERE cid=scid AND bno=sbno;

    for r as
        SELECT nofvotes FROM votes WHERE cid=scid AND bno=sbno;
    do
        set sum = sum + r.nofvotes;
    end for

    if sum > max
        then return(0);
    else
        return(1);
END
$$
1
  • 1
    There is a lot more wrong with that function. declare is only used once (before the begin) for r as .. is still wrong. And there is no set in Postgres. And the loop needs to be terminated with ; and you can't initialize in the declaration using a select. Aug 2, 2015 at 16:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.