Thread: summing tables

summing tables

From
Erik Thiele
Date:
hi,

i have a table consisting of 4 integers.

seq is for making the table ordered. (ORDER BY SEQ ASC)
a,b,c maybe null

seq | a  | b  | c 
-----+----+----+---  0 |  1 |  2 | 3  1 |  1 |  2 |    2 |  5 |  7 |    3 | -2 | -4 |  


i am needing a sql statement to do

c=a+b+"the c of the row with seq one less than myself"

this statement has to run over the whole table, in seq order.


how can this be acomplished???


cu&thanks
erik


-- 
Erik Thiele


Re: summing tables

From
"Viorel Dragomir"
Date:
update table_name
set c = a + b + (select c from table_name as x where x.seq = seq-1)
where c is null;

additional checks are required if you want to update c when c is not null
if all the c are null then this query will do nothing

god help u
:)

----- Original Message ----- 
From: "Erik Thiele" <erik@thiele-hydraulik.de>
To: <pgsql-sql@postgresql.org>
Sent: Tuesday, July 15, 2003 3:09 PM
Subject: [SQL] summing tables


> hi,
> 
> i have a table consisting of 4 integers.
> 
> seq is for making the table ordered. (ORDER BY SEQ ASC)
> a,b,c maybe null
> 
> 
>  seq | a  | b  | c 
> -----+----+----+---
>    0 |  1 |  2 | 3
>    1 |  1 |  2 |  
>    2 |  5 |  7 |  
>    3 | -2 | -4 |  
> 
> 
> i am needing a sql statement to do
> 
> c=a+b+"the c of the row with seq one less than myself"
> 
> this statement has to run over the whole table, in seq order.
> 
> 
> how can this be acomplished???
> 
> 
> cu&thanks
> erik
> 
> 
> -- 
> Erik Thiele
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org


Re: summing tables

From
Dani Oderbolz
Date:
Erik Thiele wrote:

>hi,
>
>i have a table consisting of 4 integers.
>
>seq is for making the table ordered. (ORDER BY SEQ ASC)
>a,b,c maybe null
>
>
> seq | a  | b  | c 
>-----+----+----+---
>   0 |  1 |  2 | 3
>   1 |  1 |  2 |  
>   2 |  5 |  7 |  
>   3 | -2 | -4 |  
>
>
>i am needing a sql statement to do
>
>c=a+b+"the c of the row with seq one less than myself"
>
>this statement has to run over the whole table, in seq order.
>
>
>how can this be acomplished???
>
>
>cu&thanks
>erik
>
>
>  
>
Hi Erik,
this should do the trick:
(I have not yet considered the NULLS though...)
UPDATE table t set c = a + b + (Select c from table tt where tt.seq = 
t.seq -1)

Cheers, Dani





Re: summing tables

From
Erik Thiele
Date:
On Tue, 15 Jul 2003 15:16:21 +0300
"Viorel Dragomir" <bigchief@vio.ro> wrote:

> update table_name
> set c = a + b + (select c from table_name as x where x.seq = seq-1)
> where c is null;

hmmm. the query is run row by row, isn't it?
but it will have different results depending on the order of those rows.

look, the c value is set by one row-query
and read by the row-query of the row below.

does sql specify some "order is magically always as you expect it" rule?

still i am a little confused.


and i am sorry, i didn't initially specify that the "seq" are not gapless.
i.e. seq-1 does not always exist. but seq-13 could be the next lower one!

zeit=# select * from foo;seq | a  | b  | c 
-----+----+----+---  0 |  1 |  2 | 3  1 |  1 |  2 |    2 |  5 |  7 |    3 | -2 | -4 |    6 | -1 | -2 |    5 | -2 | -2 |
  4 |  0 |  1 |  
 
(7 rows)

i created this (gapless for easiness) table and run your query:

zeit=# update foo set c = a + b + (select c from foo as x where x.seq = seq-1) where c is null;
UPDATE 6

#### 6 updates??? really???

zeit=# select * from foo;seq | a  | b  | c 
-----+----+----+---  0 |  1 |  2 | 3  1 |  1 |  2 |    2 |  5 |  7 |    3 | -2 | -4 |    6 | -1 | -2 |    5 | -2 | -2 |
  4 |  0 |  1 |  
 
(7 rows)


hmmmm. let's try the statement of the other reply to my initial mail:

UPDATE foo t set c = a + b + (Select c from foo tt where tt.seq = t.seq -1)

zeit=# UPDATE foo t set c = a + b + (Select c from foo tt where tt.seq = t.seq -1);
ERROR:  parser: parse error at or near "t"

hmmmm....

any clues?

cu & thx
erik

> additional checks are required if you want to update c when c is not null
> if all the c are null then this query will do nothing
> > i have a table consisting of 4 integers.
> > 
> > seq is for making the table ordered. (ORDER BY SEQ ASC)
> > a,b,c maybe null
> > 
> > 
> >  seq | a  | b  | c 
> > -----+----+----+---
> >    0 |  1 |  2 | 3
> >    1 |  1 |  2 |  
> >    2 |  5 |  7 |  
> >    3 | -2 | -4 |  
> > 
> > 
> > i am needing a sql statement to do
> > 
> > c=a+b+"the c of the row with seq one less than myself"
> > 
> > this statement has to run over the whole table, in seq order.

-- 
Erik Thiele


Re: summing tables

From
"Viorel Dragomir"
Date:
Ok. I disregarded the complexity of this problem. :)
You may wish to do this thing from a programming language with every row at
a time [in php, asp...].

Anyway here is a function in plpgsql.
It solves your problem, i hope; but i don't recommend it.

create function update_nulls() returns int
as '
declarevar1  integer;var2  integer;
begin   select into var1 count(*) from tab where c is null;   var2 := var1;   while var1 > 0 loopupdate table_nameset c
=a + b + (select x.c from table_name as x where x.seq =
 
table_name.seq-1)where c is null;
var1 := var1 - 1;   end loop;   return var2;
end; '
language 'plpgsql';




----- Original Message -----
From: "Erik Thiele" <erik@thiele-hydraulik.de>
To: <pgsql-sql@postgresql.org>
Sent: Tuesday, July 15, 2003 3:39 PM
Subject: Re: [SQL] summing tables


> On Tue, 15 Jul 2003 15:16:21 +0300
> "Viorel Dragomir" <bigchief@vio.ro> wrote:
>
> > update table_name
> > set c = a + b + (select c from table_name as x where x.seq = seq-1)
> > where c is null;
>
> hmmm. the query is run row by row, isn't it?
> but it will have different results depending on the order of those rows.
>
> look, the c value is set by one row-query
> and read by the row-query of the row below.
>
> does sql specify some "order is magically always as you expect it" rule?
>
> still i am a little confused.
>
>
> and i am sorry, i didn't initially specify that the "seq" are not gapless.
> i.e. seq-1 does not always exist. but seq-13 could be the next lower one!
>
> zeit=# select * from foo;
>  seq | a  | b  | c
> -----+----+----+---
>    0 |  1 |  2 | 3
>    1 |  1 |  2 |
>    2 |  5 |  7 |
>    3 | -2 | -4 |
>    6 | -1 | -2 |
>    5 | -2 | -2 |
>    4 |  0 |  1 |
> (7 rows)
>
> i created this (gapless for easiness) table and run your query:
>
> zeit=# update foo set c = a + b + (select c from foo as x where x.seq =
seq-1) where c is null;
> UPDATE 6
>
> #### 6 updates??? really???
>
> zeit=# select * from foo;
>  seq | a  | b  | c
> -----+----+----+---
>    0 |  1 |  2 | 3
>    1 |  1 |  2 |
>    2 |  5 |  7 |
>    3 | -2 | -4 |
>    6 | -1 | -2 |
>    5 | -2 | -2 |
>    4 |  0 |  1 |
> (7 rows)
>
>
> hmmmm. let's try the statement of the other reply to my initial mail:
>
> UPDATE foo t set c = a + b + (Select c from foo tt where tt.seq =
t.seq -1)
>
> zeit=# UPDATE foo t set c = a + b + (Select c from foo tt where tt.seq =
t.seq -1);
> ERROR:  parser: parse error at or near "t"
>
> hmmmm....
>
> any clues?
>
> cu & thx
> erik
>
> > additional checks are required if you want to update c when c is not
null
> > if all the c are null then this query will do nothing
> > > i have a table consisting of 4 integers.
> > >
> > > seq is for making the table ordered. (ORDER BY SEQ ASC)
> > > a,b,c maybe null
> > >
> > >
> > >  seq | a  | b  | c
> > > -----+----+----+---
> > >    0 |  1 |  2 | 3
> > >    1 |  1 |  2 |
> > >    2 |  5 |  7 |
> > >    3 | -2 | -4 |
> > >
> > >
> > > i am needing a sql statement to do
> > >
> > > c=a+b+"the c of the row with seq one less than myself"
> > >
> > > this statement has to run over the whole table, in seq order.
>
> --
> Erik Thiele
>
> ---------------------------(end of broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
>       subscribe-nomail command to majordomo@postgresql.org so that your
>       message can get through to the mailing list cleanly



Re: summing tables

From
Greg Stark
Date:
To solve this problem efficiently you probably need the lead/lag analytic
functions. Unfortunately Postgres doesn't have them.

You could do it with something like:

update foo set c = a+b+(select c from foo as x where seq < foo.seq ORDER BY seq desc LIMIT 1) 

or the more standard but likely to be way slower:

update foo set c = a+b+(select c from foo as x where seq = (select max(seq) from foo as y where seq < foo.seq))


However, i would suggest that if you have an implicit relationship between
records you should make that relationship explicit with a foreign key. If you
had a column that contained the seq of the parent record then this would be
easy. I'm really puzzled how this query as currently specified could be
useful.


-- 
greg



Re: summing tables

From
Jean-Luc Lachance
Date:
Erik,

If you intent is to get a running total of a and b ordered by seq, you
should try this (assuming the table name is t):

update t set c = ( select sum(a) + sum(b) from t t1 where t1.seq <=
t.seq);

You should have an index on seq.
If the table is very large, it is going to be painfully slow.
In that case you may want to think about using a function to step thru
each row.

JLL

Erik Thiele wrote:
> 
> hi,
> 
> i have a table consisting of 4 integers.
> 
> seq is for making the table ordered. (ORDER BY SEQ ASC)
> a,b,c maybe null
> 
>  seq | a  | b  | c
> -----+----+----+---
>    0 |  1 |  2 | 3
>    1 |  1 |  2 |
>    2 |  5 |  7 |
>    3 | -2 | -4 |
> 
> i am needing a sql statement to do
> 
> c=a+b+"the c of the row with seq one less than myself"
> 
> this statement has to run over the whole table, in seq order.
> 
> how can this be acomplished???
> 
> cu&thanks
> erik
> 
> --
> Erik Thiele
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org


Re: summing tables

From
Tom Lane
Date:
Erik Thiele <erik@thiele-hydraulik.de> writes:
> "Viorel Dragomir" <bigchief@vio.ro> wrote:
>> update table_name
>> set c = a + b + (select c from table_name as x where x.seq = seq-1)
>> where c is null;

> hmmm. the query is run row by row, isn't it?
> but it will have different results depending on the order of those rows.

No, it won't, because the SELECTs will not see the changes from the
not-yet-completed UPDATE.  The above command is almost right; it needs
to be

update table_name
set c = a + b + (select c from table_name as x where seq = table_name.seq-1)
where c is null;

because inside the sub-SELECT, unadorned "seq" will refer to the SELECT's
table.

You didn't say exactly what you wanted to do with null inputs, so that
issue may need more thought.
        regards, tom lane


Re: summing tables

From
"Viorel Dragomir"
Date:
Indeed it was a mistake not to put the table_name. in where clause.
But this doesn't resolve the problem.

Do you know in which order the update will modify the rows?
My lucky guess is that it takes from last inserted rows to the first row. In
this way only one row gets updated correctly.

I add the result from my unfortunate solution, even corrected.

select * from table_name;seq | a | b | c
-----+---+---+---  1 | 1 | 2 | 3  2 | 5 | 9 |  3 | 1 | 2 |  4 | 4 | 7 |  5 | 4 | 2 |  6 | 0 | 1 |
(6 rows)

update table_nameset c = a + b + (select c from table_name as x where seq =
table_name.seq-1)where c is null;

select * from table_name;seq | a | b | c
-----+---+---+----  1 | 1 | 2 |  3  2 | 5 | 9 | 17  3 | 1 | 2 |  4 | 4 | 7 |  5 | 4 | 2 |  6 | 0 | 1 |


----- Original Message -----
From: "Tom Lane" <tgl@sss.pgh.pa.us>
To: "Erik Thiele" <erik@thiele-hydraulik.de>
Cc: <pgsql-sql@postgresql.org>
Sent: Tuesday, July 15, 2003 6:14 PM
Subject: Re: [SQL] summing tables


> Erik Thiele <erik@thiele-hydraulik.de> writes:
> > "Viorel Dragomir" <bigchief@vio.ro> wrote:
> >> update table_name
> >> set c = a + b + (select c from table_name as x where x.seq = seq-1)
> >> where c is null;
>
> > hmmm. the query is run row by row, isn't it?
> > but it will have different results depending on the order of those rows.
>
> No, it won't, because the SELECTs will not see the changes from the
> not-yet-completed UPDATE.  The above command is almost right; it needs
> to be
>
> update table_name
> set c = a + b + (select c from table_name as x where seq =
table_name.seq-1)
> where c is null;
>
> because inside the sub-SELECT, unadorned "seq" will refer to the SELECT's
> table.
>
> You didn't say exactly what you wanted to do with null inputs, so that
> issue may need more thought.
>
> regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
>                http://www.postgresql.org/docs/faqs/FAQ.html



Re: summing tables

From
Greg Stark
Date:
"Viorel Dragomir" <bc@vio.ro> writes:

> Anyway, in real life this update modifies only one row with a value wich is
> diff of null. It was really handy if it was specified the option ORDER for
> the update command.

Are you hoping to produce a running total? That's very difficult in standard
SQL. That would be very different from the query you asked for. 

Running totals, ranking, lead/lag, are all things that are very difficult to
do in standard SQL. They don't fit in the unordered set model that SQL follows
so doing them without special non-standard functions is very hard and
inefficient. 

The functions to do them don't fit well within the SQL universe either, which
might be why they don't exist yet in postgres.

-- 
greg



Re: summing tables

From
Tom Lane
Date:
"Viorel Dragomir" <bigchief@vio.ro> writes:
> Indeed it was a mistake not to put the table_name. in where clause.
> But this doesn't resolve the problem.

> Do you know in which order the update will modify the rows?

No, and *it does not matter*.  You are forgetting that this all runs
under MVCC rules.  The sub-SELECTs will see the pre-existing versions
of the rows, whether or not the UPDATE has yet produced new versions.
        regards, tom lane


Re: summing tables

From
"Viorel Dragomir"
Date:
----- Original Message -----
From: "Tom Lane" <tgl@sss.pgh.pa.us>
To: "Viorel Dragomir" <bigchief@vio.ro>
Cc: <pgsql-sql@postgresql.org>
Sent: Tuesday, July 15, 2003 6:42 PM
Subject: Re: [SQL] summing tables


> "Viorel Dragomir" <bigchief@vio.ro> writes:
> > Indeed it was a mistake not to put the table_name. in where clause.
> > But this doesn't resolve the problem.
>
> > Do you know in which order the update will modify the rows?
>
> No, and *it does not matter*.  You are forgetting that this all runs
> under MVCC rules.  The sub-SELECTs will see the pre-existing versions
> of the rows, whether or not the UPDATE has yet produced new versions.

Yes that was correct.
I forgot that the subselect sees only the old rows.

And the ORDER option will not make any difference, only making fool out of
myself. :)
I don't know if the problem is solved with my posted function.

Anyway this is the mail that started all [i get a lot of emails and i'm not
really searching for a solution on this matter]:
"
hi,

i have a table consisting of 4 integers.

seq is for making the table ordered. (ORDER BY SEQ ASC)
a,b,c maybe null

seq | a  | b  | c
-----+----+----+---  0 |  1 |  2 | 3  1 |  1 |  2 |  2 |  5 |  7 |  3 | -2 | -4 |


i am needing a sql statement to do

c=a+b+"the c of the row with seq one less than myself"

this statement has to run over the whole table, in seq order.


how can this be acomplished???


cu&thanks
erik


--
Erik Thiele
"



Re: summing tables

From
"Viorel Dragomir"
Date:
The primary problem was that the update command doesn't modify rows in the
order u want to do it.
I think the update starts with the latest inserted rows. I guess.

Anyway, in real life this update modifies only one row with a value wich is
diff of null.
It was really handy if it was specified the option ORDER for the update
command.

----- Original Message -----
From: "Greg Stark" <gsstark@mit.edu>
To: "Viorel Dragomir" <bigchief@vio.ro>
Cc: <pgsql-sql@postgresql.org>
Sent: Tuesday, July 15, 2003 5:55 PM
Subject: Re: [SQL] summing tables


>
> To solve this problem efficiently you probably need the lead/lag analytic
> functions. Unfortunately Postgres doesn't have them.
>
> You could do it with something like:
>
> update foo set c = a+b+(select c from foo as x where seq < foo.seq ORDER
BY seq desc LIMIT 1)
>
> or the more standard but likely to be way slower:
>
> update foo set c = a+b+(select c from foo as x where seq = (select
max(seq) from foo as y where seq < foo.seq))
>
>
> However, i would suggest that if you have an implicit relationship between
> records you should make that relationship explicit with a foreign key. If
you
> had a column that contained the seq of the parent record then this would
be
> easy. I'm really puzzled how this query as currently specified could be
> useful.
>
>
> --
> greg
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 4: Don't 'kill -9' the postmaster