X-Original-To: pgsql-sql-postgresql.org@localhost.postgresql.org Received: from localhost (av.hub.org [200.46.204.144]) by postgresql.org (Postfix) with ESMTP id DB1829DC88B for ; Tue, 13 Dec 2005 22:04:33 -0400 (AST) Received: from postgresql.org ([200.46.204.71]) by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024) with ESMTP id 03938-01 for ; Tue, 13 Dec 2005 22:04:37 -0400 (AST) X-Greylist: domain auto-whitelisted by SQLgrey- Received: from xproxy.gmail.com (xproxy.gmail.com [66.249.82.197]) by postgresql.org (Postfix) with ESMTP id 6FCD19DC85A for ; Tue, 13 Dec 2005 22:04:31 -0400 (AST) Received: by xproxy.gmail.com with SMTP id s14so4735wxc for ; Tue, 13 Dec 2005 18:04:35 -0800 (PST) DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com; h=received:message-id:date:from:subject:cc:in-reply-to:mime-version:content-type:references; b=NsFhxP4x+nOGzqU+PegQZOzUQ1M/CAdx7g8IseQHYM+UB8LqlSWiIhgsYwmXqIAE7ksXUcewvh8fTO8pWI41ArIkOgYuK1wJFUdgF/ZtBI6JngYRxcNcPVcPt/RwumGL7hpUSg5hPXdqkci+30oAIx1WZ0X5KWlCy36UhV+iUPo= Received: by 10.70.16.19 with SMTP id 19mr95182wxp; Tue, 13 Dec 2005 18:04:35 -0800 (PST) Received: by 10.70.48.10 with HTTP; Tue, 13 Dec 2005 18:04:35 -0800 (PST) Message-ID: <1319fbba0512131804v55dd3f24h3cddf5b10ef70a0c@mail.gmail.com> Date: Tue, 13 Dec 2005 18:04:35 -0800 From: Aaron Koning Subject: Re: Multi-row update w. plpgsql function Cc: "postgreSQL (SQL)" In-Reply-To: <144D12D7DD4EC04F99241498BB4EEDCC18FFE2@nelson.osl.com> MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_Part_33646_28456223.1134525875776" References: <144D12D7DD4EC04F99241498BB4EEDCC18FFE2@nelson.osl.com> X-Virus-Scanned: by amavisd-new at hub.org X-Spam-Status: No, score=0.096 required=5 tests=[AWL=-0.095, HTML_MESSAGE=0.001, MISSING_HEADERS=0.189] X-Spam-Score: 0.096 X-Spam-Level: X-Archive-Number: 200512/108 X-Sequence-Number: 23650 ------=_Part_33646_28456223.1134525875776 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Owen makes a good point. Check that you are using the [] in the HTML input variable for the checkboxes. Like: 1
2
3
4
Aaron On 12/13/05, Owen Jacobson wrote: > > Daniel Hertz wrote: > > > Given a set of checkbox values that are submitted through an > > html form, > > how do you loop through the submitted values to update more > > than one row > > in a table? > > > > Imagine a table called 'message_table': > > > > mid | message | status > > ----+---------+------- > > 1 | Text1 | H > > 2 | Text2 | H > > 3 | Text3 | H > > 4 | Text4 | H > > > > A web page presents the user with all messages flagged with 'H'. User > > checks messages 1,3 and 4 and submits form. > > (i.e. approved=3D1&approved=3D3&approved=3D4) > > > > After performing postgreSQL update, rows 1, 3 and 4 would be > > updated to: > > > > mid | message | status > > ----+---------+------- > > 1 | Text1 | A > > 2 | Text2 | H > > 3 | Text3 | A > > 4 | Text4 | A > > BEGIN; > UPDATE message_table SET status =3D 'A' WHERE mid =3D 1; > UPDATE message_table SET status =3D 'A' WHERE mid =3D 3; > UPDATE message_table SET status =3D 'A' WHERE mid =3D 4; > COMMIT; > > would do that. Have your application generate an appropriate UPDATE line > for each "approved" entry in the form data, wrap it in a transaction, and > away you go. > > > I have never written a plpgsql function, but tried: > > > > CREATE OR REPLACE FUNCTION update_messages(approved integer) RETURNS > > integer AS > > $body$ > > DECLARE > > new_status varchar; > > new_sample record; > > > > BEGIN > > new_status :=3D 'A'; > > > > FOR new_sample IN SELECT * FROM message_table WHERE > > status=3D'H' ORDER BY > > mid LOOP > > 1. No need for ORDER BY here, we're not doing anything user-visible or > order-dependent with the data, so it's a waste of CPU time. > 2. You're not using new_sample for anything, just retrieving it. > > > UPDATE message_table SET status =3D new_status > > WHERE mid =3D approved; > > Consider that you can only pass a single value to an INTEGER parameter > ("approved"); this will repeatedly update a single entry where mid =3D > approved. You could simplify the function as written to > > CREATE OR REPLACE FUNCTION update_messages (INTEGER) RETURNS VOID AS $$ > UPDATE message_table SET status =3D 'A' WHERE mid =3D $1; > $$ LANGUAGE SQL; > > > END LOOP; > > > > RETURN 1; > > END; > > $body$ > > LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER; > > > > I call the function with: > > SELECT update_messages(); > > > > I'm using apache cocoon, which is why you see the variable > > placeholder: > > ); > > I'm not familiar with Cocoon, but I'd expect that to return only the firs= t > of the "approved" values from the HTTP request. If you add logging to th= e > stored function (RAISE NOTICE 'approved: %', approved; near the start of = the > function, for instance) and tell PostgreSQL to store the logs, you can se= e > what values your function is actually being called with. > > What you really want to do is begin a transaction, loop over all the > values of approved present in the form data and call (the rewritten versi= on > of) update_messages for each one, then commit the transaction. > > -Owen > > ---------------------------(end of broadcast)--------------------------- > TIP 2: Don't 'kill -9' the postmaster > ------=_Part_33646_28456223.1134525875776 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Owen makes a good point. Check that you are using the [] in the HTML input = variable for the checkboxes. Like:

<input type=3D"checkbox" name=3D"approved[]" value= =3D"1" /> 1 <br/>
<input type=3D"checkbox" name=3D"approved[]" value= =3D"2" /> 2 <br/>
<input type=3D"checkbox" name=3D"approved[]" value= =3D"3" /> 3 <br/>
<input type=3D"checkbox" name=3D"approved[]" value= =3D"4" /> 4 <br/>

Aaron

On 12/13/05, Owen Jacobson <oj= acobson@osl.com> wrote:
Daniel Hertz wrote:

> Given a set of checkbox values that are sub= mitted through an
> html form,
> how do you loop through the su= bmitted values to update more
> than one row
> in a table?
>
> Imagine a table called 'message_table':
>
> mid | = message | status
> ----+---------+-------
>   1 =  |  Text1   |  H
>   2&n= bsp; |  Text2   |  H
>  = 3  |  Text3   |  H
> &n= bsp; 4  |  Text4   |  H
>
> A web page presents the user with all messages flagged wit= h 'H'. User
> checks messages 1,3 and 4 and submits form.
> (i.= e. approved=3D1&approved=3D3&approved=3D4)
>
> After pe= rforming postgreSQL update, rows 1, 3 and 4 would be
> updated to:
>
> mid | message | status
> ----+--= -------+-------
>   1  |  Text1 &n= bsp; |  A
>   2  |  Text2&nbs= p;  |  H
>   3  |  Text3=    |  A
>   4  |  T= ext4   |  A

BEGIN;
UPDATE message_table SET status =3D 'A' WHERE mid =3D 1;
UPDATE message_= table SET status =3D 'A' WHERE mid =3D 3;
UPDATE message_table SET statu= s =3D 'A' WHERE mid =3D 4;
COMMIT;

would do that.  Have your application generate an appropriate UPDATE line for each "approved" entry in the form data, wrap it i= n a transaction, and away you go.

> I have never written a plpgsql fu= nction, but tried:
>
> CREATE OR REPLACE FUNCTION update_messag= es(approved integer) RETURNS
> integer AS
> $body$
> DECL= ARE
>  new_status varchar;
>  new_sample recor= d;
>
> BEGIN
>  new_status :=3D 'A';
>>  FOR new_sample IN SELECT * FROM message_table WHERE
>= ; status=3D'H' ORDER BY
> mid LOOP

1.  No need for ORDER BY here, we're not doing anything user-visible or order-dependent with the data, so it's a waste of CPU time.
2. &nbs= p;You're not using new_sample for anything, just retrieving it.

>=    UPDATE message_table SET status =3D new_status
> &n= bsp; WHERE mid =3D approved;

Consider that you can only pass a single value to an INTEGER parameter ("approved"); this will repeatedly update a single entry where mi= d =3D approved.  You could simplify the function as written to

C= REATE OR REPLACE FUNCTION update_messages (INTEGER) RETURNS VOID AS $$
&= nbsp; UPDATE message_table SET status =3D 'A' WHERE mid =3D $1;
$$ = LANGUAGE SQL;

>  END LOOP;
>
>  RETURN 1;
> END;=
> $body$
> LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SE= CURITY INVOKER;
>
> I call the function with:
> SELECT up= date_messages(<xsp-request:get-parameter name=3D"approved"/>= ;);
>
> I'm using apache cocoon, which is why you see the variable=
> placeholder:
> <xsp-request:get-parameter name=3D"ap= proved"/>);

I'm not familiar with Cocoon, but I'd expect that to return only the first of the "approved" values from the HTTP request.  If you= add logging to the stored function (RAISE NOTICE 'approved: %', approved; near the start of the function, for instance) and tell PostgreSQL to store the logs, you can see what values your function is actually being called with.

What you really want to do is begin a transaction, loop over all the values of approved present in the form data and call (the rewritten version of) update_messages for each one, then commit the transaction.

-Owen

---------------------------(end of bro= adcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster=

------=_Part_33646_28456223.1134525875776--