Thread: Tricky SQL (?)
Let's say I have a table of credits with a customer number attached to it and a table of refunds with a customer number attached to it. Occasionally I want to go through this list and check if any customers still have more credits summed up than refunds. The technically correct choice for a query would be something like SELECT customer_nr, sum(amount) FROM ( SELECT customer_nr, amount FROM credits UNION customer_nr, -amount FROM refunds ) GROUP BY customer_nr HAVING sum(amount)>0; Unfortunately, this doesn't work because subselects are not allowed in the target list. The current solution is to read in all credits and refunds and have the application (some PHP, some Perl) do the summing and filtering. But this doesn't only seem clumsy but it creates unneccessay network traffic. Seemingly, this should be a common problem, like invoices vs. payments, assets vs. liabilities, etc. Does anyone have suggestions on how to tackle this? I am open to changes in the table structure, too. -- Peter Eisentraut PathWay Computing, Inc.
Use a temporary table. Peter Eisentraut wrote: > > Let's say I have a table of credits with a customer number attached to it > and a table of refunds with a customer number attached to it. Occasionally > I want to go through this list and check if any customers still have > more credits summed up than refunds. > > The technically correct choice for a query would be something like > > SELECT customer_nr, sum(amount) FROM ( SELECT customer_nr, amount FROM > credits UNION customer_nr, -amount FROM refunds ) GROUP BY customer_nr > HAVING sum(amount)>0; > > Unfortunately, this doesn't work because subselects are not allowed in the > target list. The current solution is to read in all credits and refunds > and have the application (some PHP, some Perl) do the summing and > filtering. But this doesn't only seem clumsy but it creates unneccessay > network traffic. > > Seemingly, this should be a common problem, like invoices vs. payments, > assets vs. liabilities, etc. Does anyone have suggestions on how to tackle > this? I am open to changes in the table structure, too. > > -- > Peter Eisentraut > PathWay Computing, Inc. -- Chris Bitmead mailto:chris@tech.com.au http://www.techphoto.org - Photography News, Stuff that Matters
At 00:04 +0300 on 03/07/1999, Peter Eisentraut wrote: > Unfortunately, this doesn't work because subselects are not allowed in the > target list. The current solution is to read in all credits and refunds > and have the application (some PHP, some Perl) do the summing and > filtering. But this doesn't only seem clumsy but it creates unneccessay > network traffic. It seems that the current solution would be to create a temporary table, where you dump the results of your internal query, and then do the external select. Would be more efficient than doing it on the frontend (network traffic and all). Version 6.5 has a facility for naming temporary tables so that you don't have to worry about exclusive names in a multiuser environment. If you are using a previous version, you should worry about this only if more than one person uses said query at a time. Otherwise you should use a preexisting table, and lock it prior to the query, which would mean another user needs to wait until the first user finishes the query. All that said, the solution would be [I haven't tested]: CREATE TEMP TABLE int_qry ( customer_nr int4, amount decimal(2) ); BEGIN; INSERT INTO int_qry( customer_nr, amount) SELECT customer_nr, amount FROM credits UNION customer_nr, -amount FROM refunds; SELECT customer_nr, sum(amount) FROM int_qry GROUP BY customer_nr HAVING sum(amount) > 0; END; DROP TABLE int_qry; I inserted the BEGIN and END just to assert that the two operations are in fact a single operation. Since temporary tables only exist in one session, there is little danger of multiple queries messing with each other's results. Herouth -- Herouth Maoz, Internet developer. Open University of Israel - Telem project http://telem.openu.ac.il/~herutma