[SQL] Looking for a way to sum integer arrays....
I'd like to be able to sum up an integer array. Like so:
{3,2,1}
+ {0,2,2}
---
{3,4,3}
The following solution I've been hacking on works, although I think it
is far from "ideal". Is there a built in way to sum up arrays? If not,
is there a better way than my crude method? I have tested this on 7.4
and 8.0. I'd also be appreciate if any insight on why my aggregate
fails to work when I have an empty initcondition. P.S. I have never
written an aggregate and I was lost trying to follow the complex_sum
example in the docs.
-
CREATE OR REPLACE FUNCTION sum_intarray(INTEGER[],INTEGER[]) RETURNS
INTEGER[] LANGUAGE 'plpgsql' AS '
/*
|| Author: Tony Wasson
||
|| Overview: Experiment with arrays and aggregates
|| 3,2,1
||+ 0,2,2
|| ---
|| 3,4,3
||
|| Revisions: (when, who, what)
|| 2005/04/21 -- TW - Create function
*/
DECLARE
inta1 ALIAS FOR $1;
inta2 ALIAS FOR $2;
out_arr INTEGER[];
out_arr_textTEXT := '''';
i INTEGER;
nextnum INTEGER;
BEGIN
FOR i IN array_lower(inta1, 1)..array_upper(inta1, 1)
LOOP
RAISE NOTICE ''looking at element %'',i;
nextnum := COALESCE(inta1[i],0) + COALESCE(inta2[i],0);
RAISE NOTICE ''nextnum %'',nextnum;
out_arr_text := out_arr_text || nextnum::TEXT || '','';
RAISE NOTICE ''text %'',out_arr_text;
END LOOP;
RAISE NOTICE ''text %'',out_arr_text;
--drop the last comma
IF SUBSTRING(out_arr_text,length(out_arr_text),1) = '','' THEN
out_arr_text := substring(out_arr_text,1,length(out_arr_text)-1);
END IF;
out_arr_text := ''{'' || out_arr_text || ''}'';
RAISE NOTICE ''text %'',out_arr_text;
out_arr := out_arr_text;
RAISE NOTICE ''out_arr %'',out_arr;
RETURN out_arr;
END
';
SELECT sum_intarray('{1,2}','{2,3}');
SELECT sum_intarray('{3,2,1}','{0,2,2}');
--- Now I make a table to demonstrate an aggregate on
CREATE TABLE arraytest (
id character varying(10) NOT NULL,
somearr integer[]
);
INSERT INTO arraytest (id, somearr) VALUES ('a', '{1,2,3}');
INSERT INTO arraytest (id, somearr) VALUES ('b', '{0,1,2}');
CREATE AGGREGATE sum_integer_array (
sfunc = sum_intarray,
basetype = INTEGER[],
stype = INTEGER[],
initcond =
'{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}'
);
--
# SELECT sum_integer_array(somearr) FROM arraytest;
sum_integer_array
-
{1,3,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
Thanks in advance to anyone who reads this far.
Tony Wasson
[EMAIL PROTECTED]
---(end of broadcast)---
TIP 3: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to [EMAIL PROTECTED] so that your
message can get through to the mailing list cleanly
Re: [SQL] Looking for a way to sum integer arrays....
Thank you for the responses!
To recap: pl/r array support works very well. In my case, I am looking
for pl/pgsql solution.
I also got this nice function from dennisb on the #postgresql irc
channel, which seems extremely "clean" and works with 7.4/8.0. My
original function didn't handle a blank initcond in the aggregate
gracefully.
CREATE OR REPLACE FUNCTION array_add(int[],int[]) RETURNS int[] AS '
DECLARE
x ALIAS FOR $1;
y ALIAS FOR $2;
a int;
b int;
i int;
res int[];
BEGIN
res = x;
a := array_lower (y, 1);
b := array_upper (y, 1);
IF a IS NOT NULL THEN
FOR i IN a .. b LOOP
res[i] := coalesce(res[i],0) + y[i];
END LOOP;
END IF;
RETURN res;
END;
'
LANGUAGE plpgsql STRICT IMMUTABLE;
--- then this aggregate lets me sum integer arrays...
CREATE AGGREGATE sum_integer_array (
sfunc = array_add,
basetype = INTEGER[],
stype = INTEGER[],
initcond = '{}'
);
Here's how my sample table looked and my new array summing aggregate
and function:
#SELECT * FROM arraytest ;
id | somearr
+-
a | {1,2,3}
b | {0,1,2}
(2 rows)
#SELECT sum_integer_array(somearr) FROM arraytest ;
sum_integer_array
-------
{1,3,5}
(1 row)
Tony Wasson
---(end of broadcast)---
TIP 8: explain analyze is your friend
Re: [SQL] default value for select?
On 5/9/05, Mark Fenbers <[EMAIL PROTECTED]> wrote: > I want to update a column in myTable. The value this column is set to > depends on a nested select statement which sometimes returns 0 rows instead > of 1. This is a problem since the column I'm trying to update is set to > refuse nulls. Here's a sample: > > update myTable set myColumn = (Select altColumn from altTable where > altColumn != 'XXX' limit 1) where myColumn = 'XXX'; > > MyColumn cannot accept nulls, but sometimes "Select altColumn ..." returns > 0 rows, and thus, the query fails. > > Is there a way to set a default value to be inserted into myColumn if and > when "select altColumn ..." returns zero rows? > > Mark Mark, You can work around this by using a CASE statement. In this case, test for a NULL from your subquery. This is not elegant at all, but it should do what you are wanting. update myTable set myColumn = (CASE WHEN (Select altColumn from altTable where altColumn != 'XXX' limit 1) IS NULL THEN 'some default value' ELSE (Select altColumn from altTable where altColumn != 'XXX' limit 1) END) where myColumn = 'XXX'; Hope this helps... Tony ---(end of broadcast)--- TIP 5: Have you checked our extensive FAQ? http://www.postgresql.org/docs/faq
Re: [SQL] Help: Function for splitting VARCHAR column and migrating its data to 2 new tables
able('%');
The input goes to a SIMILAR TO on id - and % means all elements. You
can match a single row by using something like SELECT
build_keyword_table('123');
I also used this as my test data... It worked for me!
CREATE TABLE user_data (
id SERIAL,
user_id INTEGER,
keywords VARCHAR(256) NOT NULL,
add_date TIMESTAMP,
PRIMARY KEY(id)
);
INSERT INTO user_data (keywords) VALUES ('new york,san francisco,
dallas, food');
INSERT INTO user_data (keywords) VALUES ('phoenix, hot, summer, fun');
CREATE TABLE keyword (
name VARCHAR(64) NOT NULL,
id SERIAL,
add_date TIMESTAMP,
PRIMARY KEY(name)
);
-- todo put a UNIQUE INDEX on keyword (id)
I hope this helps.
Tony Wasson
---(end of broadcast)---
TIP 1: subscribe and unsubscribe commands go to [EMAIL PROTECTED]
Re: [SQL] 3 tables, slow count(*), order by Seq Scan in Query Plan
On 5/26/05, [EMAIL PROTECTED] <[EMAIL PROTECTED]> wrote: > Hello, > > I have 3 tables (2 tables + 1 lookup table that ties them) and running > a straight-forward aggregate count(*) query with a couple of joins > takes about 10 seconds (and I need it to be sub-second or so). > Also, I am wondering if this approach is scalable with my row-counts > and my hardware (below). > > My slow query is this: > -- > SELECT keyword.name, count(*) > FROM user_data, user_data_keyword, keyword > WHERE (user_data.user_id = 1) > AND (user_data.id = user_data_keyword.user_data_id) > AND (user_data_keyword.keyword_id = keyword.id) > GROUP BY keyword.name > ORDER BY COUNT(*) DESC LIMIT 10; > Is there any way of speeding up my query? > > Also, given the number of rows expected in those tables: > user_data: 10M > user_data_keyword: 40M > keyword:4M This sounds like a perfect candidate for a summary table. You should read Jonathan Gardner's writeup about materialized views. Depending on your requirements, you'll either need to build triggers or a periodic summarization you run. This sounds like a "top N" report so a periodic update out to work. http://jonathangardner.net/PostgreSQL/materialized_views/matviews.html Tony Wasson ---(end of broadcast)--- TIP 8: explain analyze is your friend
Re: [SQL] left joins
On 7/6/05, Ragnar Hafstaư <[EMAIL PROTECTED]> wrote: > On Wed, 2005-07-06 at 11:33 +0100, Nick Stone wrote: > > I've had exactly yhe same problem - try changing the query to. > > > > select count(*) > > from h left join p using (r,pos) and p.r_order=1 > > where h.tn > 20 > > and h.tn < 30 > > really ? is this legal SQL ? > is this a 8.0 feature ? > I get syntax error at or near "and" at character 41 > SQL like this works for me when I write it with an ON statement instead of a USING. select count(*) from h left join p on (h.r=p.r and h.pos=r.pos and p.r_order=1) where h.tn > 20 and h.tn < 30 Filtering within the join condition is very useful when doing a left outer join. Here's another example "from the book" doing this type of filter within the join: http://www.postgresql.org/docs/8.0/interactive/queries-table-expressions.html Tony Wasson ---(end of broadcast)--- TIP 2: you can get off all lists at once with the unregister command (send "unregister YourEmailAddressHere" to [EMAIL PROTECTED])
Re: [SQL] funstions for parsing words
On 7/19/05, John Kopanas <[EMAIL PROTECTED]> wrote: > I have a table called Phrases that holds the text of a phrase. I want > write a query that will return all the words found in all the text of > the Phrases. Like so: > > > Phrases: > > "Hello World" > "Goodbye World" > "I like candy > > Words (select statement result): > > "Hello" > "World" > "Goodbye" > "I" > "Like" > "Candy" > > Is anything like this possible? > > Thanks alot. > > Your Friend, > > John Kopanas You can do this by using array_to_string and using a space as your delimiter. If you need to trim the quotes use the trim function also. You can also see the split_on_commas example below -- you'd want to split on a space. I would also rewrite this to use array_to_string or use pl/perl if you can. http://archives.postgresql.org/pgsql-sql/2005-05/msg00204.php Hope this helps. Tony Wasson ---(end of broadcast)--- TIP 2: Don't 'kill -9' the postmaster
Re: [SQL] echo/printf function in plpgsql
On 7/19/05, Andreas Joseph Krogh <[EMAIL PROTECTED]> wrote: > On Tuesday 19 July 2005 17:18, Richard Huxton wrote: > > Andreas Joseph Krogh wrote: > > > Hi all! > > > > > > Is there a way of echo'ing a string(like "raise notice 'this is id%', > > > id") from plpgsql? I want to echo/print it to STDOUT 'cause the > > > notice-mechanism produces too much noise IMH. > > > > Your function is running in the backend. You don't have a STDOUT > > (although you might have redirected STDERR for logging). > > I see. Can I make the ouput somehow less verbose? It spits out a lot of noise > for each "NOTICE": You can control the severity messages sent to your client by first setting client_min_message. Try SET client_min_messages = WARNING; http://www.postgresql.org/docs/8.0/interactive/runtime-config.html Tony ---(end of broadcast)--- TIP 6: explain analyze is your friend
Re: [SQL] Multi-column returns from pgsql
On 7/22/05, Jim Buttafuoco <[EMAIL PROTECTED]> wrote: > Mark, > > Instead of RETURN NEXT rec.txt1; RETURN NEXT rec.txt2; just use RETURN NEXT > rec; > > then your select statement would be > select * from my_func() as (txt1 text,txt2 text); > > Jim Besides a simple RETURN NEXT, you'll need to return a SETOF some composite type. You can do something like CREATE TYPE twotexts_t AS (txt1 TEXT, txt2 TEXT); CREATE OR REPLACE FUNCTION my_func() returns SETOF twotexts_t AS ' DECLARE rec record; BEGIN FOR rec IN SELECT txt1, txt2 FROM mytable LOOP RETURN NEXT END LOOP; RETURN; END;' language 'plpgsql'; ---(end of broadcast)--- TIP 6: explain analyze is your friend
Re: [SQL] psql client: technique for applying default values to :variables?
On 1/11/06, Jeff Boes <[EMAIL PROTECTED]> wrote:
> Stumped: is there any way to set up default values for psql variables
> within the .SQL file itself? Obviously, I can do something like:
>
> $ psql -f my_script -v MYVAR=${myvar:-mydefault}
>
> but I would prefer to have the value stored with the .SQL file, e.g. (if
> this actually worked):
>
> \set MYVAR COALESCE(:MYVAR,'mydefault')
Stuff like this works for me in a SQL file
\set edate 'CURRENT_DATE::DATE'
SELECT * FROM some_table WHERE update_date = :edate;
---(end of broadcast)---
TIP 1: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to [EMAIL PROTECTED] so that your
message can get through to the mailing list cleanly
Re: [SQL] Function Dependency
On 2/1/06, Padam J Singh <[EMAIL PROTECTED]> wrote: > Hello, > > I am maintaining an application that has over 400 procedures and functions > written in plsql, and around 100 tables. > I want to generate a function dependency chart to depict the following: > > 1. Inter function/procedure dependencies > 2. function-tables dependencies > 3. function-sequences depencies > > Is there a standard method of doing this? > > Thanks in advance, > Padam. I too would be interested in a standardized tool to do this. I had a similar situation and I ended up writing a perl script to parse my SQL and make a graphviz dot file. I then used graphviz to make a function dependency chart. I can't promise it would catch every single case, but I can provide you with the code if you wish to give it a whirl. Tony Wasson ---(end of broadcast)--- TIP 4: Have you searched our list archives? http://archives.postgresql.org
Re: [SQL] help..postgresql mulyiple return values
On 5/12/06, Michael Joseph Tan <[EMAIL PROTECTED]> wrote: hi, im new in postgresql, generally new in databases. im trying to make a function using PGAdminIII which returns several types, example, my query is: "select count(id) as requests, organization from connection_requests group by organization" id is of type int8, organization is of type varchar(50). basically the query would return coun(id), and a varchar(50) which is organization. i really dont know what to put on the return type. what would be the best solution? If you are in 8.1 you can follow this example from the documentation. http://www.postgresql.org/docs/8.1/interactive/plpgsql-declarations.html CREATE FUNCTION sum_n_product(x int, y int, OUT sum int, OUT prod int) AS $$ BEGIN sum := x + y; prod := x * y; END; $$ LANGUAGE plpgsql; Then run it like: SELECT sum, prod FROM sum_n_product(1,2); ---(end of broadcast)--- TIP 6: explain analyze is your friend
Re: [SQL] How to pass array of values to a stored procedure
On 7/18/06, Curtis Scheer <[EMAIL PROTECTED]> wrote:
Does anyone have any examples of how I would make a stored procedure in
plpgsql that would allow for passing a list or arrays of values to be used
in an sql IN clause? Like so: select * from table where field1 in (values).
Here's a very simple example. However, I think passing arrays of INTs
around is dirty. I wasn't able to do this without a FOR ...IN EXECUTE
statement.
CREATE TABLE ids
(
id INTEGER
, PRIMARY KEY (id)
);
INSERT INTO ids VALUES (1);
INSERT INTO ids VALUES (2);
INSERT INTO ids VALUES (3);
CREATE OR REPLACE FUNCTION example_array_input(INT[]) RETURNS SETOF ids AS
$BODY$
DECLARE
in_clause ALIAS FOR $1;
clause TEXT;
rec RECORD;
BEGIN
-- conver the array to a text string and make it LOOK like an
IN statement
clause := in_clause;
clause := trim(leading '{' FROM clause);
clause := trim(trailing '}' FROM clause);
FOR rec IN EXECUTE 'SELECT id FROM ids WHERE id IN (' || clause || ');'
LOOP
RETURN NEXT rec;
END LOOP;
-- final return
RETURN;
END
$BODY$ language plpgsql;
SELECT * FROM example_array_input('{1,2,4,5,6}'::INT[]);
---(end of broadcast)---
TIP 5: don't forget to increase your free space map settings
Re: [SQL] How to pass array of values to a stored procedure
On 7/18/06, Tony Wasson <[EMAIL PROTECTED]> wrote:
On 7/18/06, Curtis Scheer <[EMAIL PROTECTED]> wrote:
> Does anyone have any examples of how I would make a stored procedure in
> plpgsql that would allow for passing a list or arrays of values to be used
> in an sql IN clause? Like so: select * from table where field1 in (values).
>
Ahhh... Here's an example using Tom's recommended field=ANY (arrayvalue) SQL.
CREATE TABLE ids
(
id INTEGER
, PRIMARY KEY (id)
);
INSERT INTO ids VALUES (1);
INSERT INTO ids VALUES (2);
INSERT INTO ids VALUES (3);
CREATE OR REPLACE FUNCTION example_array_input(INT[]) RETURNS SETOF ids AS
$BODY$
DECLARE
in_clause ALIAS FOR $1;
clause TEXT;
rec RECORD;
BEGIN
FOR rec IN SELECT id FROM ids WHERE id = ANY(in_clause)
LOOP
RETURN NEXT rec;
END LOOP;
-- final return
RETURN;
END
$BODY$ language plpgsql;
SELECT * FROM example_array_input('{1,2,4,5,6}'::INT[]);
---(end of broadcast)---
TIP 6: explain analyze is your friend
Re: [SQL] Remote monitoring of Postgres w/minimal grants
On Wed, Mar 10, 2010 at 12:26 AM, Bryce Nesbitt wrote: > I'm setting up remote monitoring of postgres, but running into an > uncomfortable situation with permissions. > Basically it seems hard to set up a secure "read only" role, yet also allow > proper monitoring. > > A brief writeup of that is here: > > http://help.logicmonitor.com/installation-getting-started/notes-for-monitoring-specific-types-of-hosts/databases/postgresql/postgresql-credentials/ > In order to get accurate server busy stats and max query time, the > LogicMonitor user needs to be a superuser "alter role logicmonitor > superuser;". Without the SuperUser privilege, all servers will appear busy, > and maximum query time will always be 0. > > Is there a way to grant the type of permission needed to view stats, > without superuser? > Seems like you could get around most of these cases by making a function or set returning function to return the data and making it "security definer" and then grant your monitoring user access to that. Tony
Re: [SQL] accounting schema
On Feb 6, 2008 6:08 PM, Medi Montaseri <[EMAIL PROTECTED]> wrote: > I am learning my way into Accounting and was wondering how Accounting > applications are designed. perhaps you could point the way > As a DBA, (and keeping it simple) I am thinking I need a table for every > account which migh look like > > id, description, credit, debit, validated, created_on, created_by, > modified_on, modified_by > > Is that pretty match it ? > Please let me know if you have seen some accounting or DB book that > addresses this problem domain. Another codebase to look at is http://www.sql-ledger.org/. It uses postgresql. Regards, Tony ---(end of broadcast)--- TIP 5: don't forget to increase your free space map settings
Re: [SQL] Can COPY update or skip existing records?
On Tue, Sep 30, 2008 at 5:16 AM, Glenn Gillen <[EMAIL PROTECTED]> wrote: > Hey all, > > I've got a table with a unique constraint across a few fields which I > need to regularly import a batch of data into. Is there a way to do it > with COPY without getting conflicts on the unique contraint? I have no > was of being certain that some of the data I'm trying to load isn't in > the table already. > > Ideally I'd like it to operate like MySQL's on_duplicate_key_update > option, but for now I'll suffice with just ignoring existing rows and > proceeding with everything else. I ran into a similar problem. I'm using these merge_by_key functions: http://pgfoundry.org/projects/mbk Here's a quick example... CREATE TEMP TABLE foo (LIKE dst INCLUDING DEFAULTS); COPY foo (c1, c2) FROM STDIN; (your copy data here) \. SELECT * FROM merge_by_key( 'public', -- table schema 'dst', -- table name 'mnew.c2 < mold.c2', -- merge condition 'select c1,c2 FROM foo' ); Disclaimer: The author is a friend of mine. :-) -- Sent via pgsql-sql mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-sql
Re: [SQL] grouping/clustering query
On Fri, Oct 24, 2008 at 8:04 AM, Steve Midgley <[EMAIL PROTECTED]> wrote:
> At 11:28 AM 10/23/2008, Joe wrote:
>>
>> Steve Midgley wrote:
# (invoiceid, txid)
(A, 1)
(A, 3)
(B, 1)
(B, 2)
(C, 5)
(D, 6)
(D, 7)
(E, 8)
(F, 8)
For journalling, I need to group/cluster this together. Is there a SQL
query that can generate this output:
# (journal: invoiceids, txids)
[A,B] , [1,2,3]
[C], [5]
[D], [6,7]
[E,F], [8]
>>>
>>> Hi Dave,
>>>
>>> I'm not following the logic here. A has 1,3 and B has 1,2. So why does
>>> the first line print:
>>>
[A,B] , [1,2,3]
>>>
>>> What's the rule that tells the query to output this way? Is it that all
>>> of B's values are between A's values?
>>
>> From a purely accounting standpoint, since transaction 1 was applied to
>> both invoices A and B, you need to group the invoices so that you can
>> compare total invoiced against total paid.
>
> I tinkered around briefly but didn't come up with a good idea, but I bet
> someone on this list can. However, I did create a CREATE script for your
> table design which, in my experience, makes it more likely that a real
> expert will take on your problem..
>
> Hope this helps,
>
> Steve
>
> DROP TABLE IF EXISTS trans;
>
> CREATE TABLE trans
> (
> id serial NOT NULL,
> inv_id character varying,
> tx_id character varying,
> CONSTRAINT pk_id PRIMARY KEY (id)
> )
> WITH (OIDS=FALSE);
>
> insert into trans (inv_id, tx_id) values('A','1');
> insert into trans (inv_id, tx_id) values('A','3');
> insert into trans (inv_id, tx_id) values('B','1');
> insert into trans (inv_id, tx_id) values('B','2');
> insert into trans (inv_id, tx_id) values('C','5');
> insert into trans (inv_id, tx_id) values('D','6');
> insert into trans (inv_id, tx_id) values('D','7');
> insert into trans (inv_id, tx_id) values('E','8');
> insert into trans (inv_id, tx_id) values('F','8');
This is as close as I can get the data. I think I'd need a custom
array grouping aggregate to get the results to match completely.
Notice how ABC are on their own lines?
test=# SELECT inv_array, tx_array
FROM (
SELECT tx_id, array_accum(inv_id) AS inv_array
FROM trans
GROUP BY tx_id
ORDER BY tx_id
) AS t
JOIN (
SELECT inv_id, array_accum(tx_id) AS tx_array
FROM trans
GROUP BY inv_id
ORDER BY inv_id
) AS i ON (t.tx_id = ANY(i.tx_array) OR i.inv_id =ANY(t.inv_array))
GROUP BY tx_array,inv_array
;
inv_array | tx_array
---+--
{A,B} | {1,2}
{B} | {1,2}
{A} | {1,3}
{A,B} | {1,3}
{C} | {5}
{D} | {6,7}
{E,F} | {8}
(7 rows)
--
Sent via pgsql-sql mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-sql
Re: [SQL] grouping/clustering query
On Fri, Oct 24, 2008 at 10:24 AM, Tony Wasson <[EMAIL PROTECTED]> wrote:
> On Fri, Oct 24, 2008 at 8:04 AM, Steve Midgley <[EMAIL PROTECTED]> wrote:
>> At 11:28 AM 10/23/2008, Joe wrote:
>>>
>>> Steve Midgley wrote:
>>>>>
>>>>> # (invoiceid, txid)
>>>>> (A, 1)
>>>>> (A, 3)
>>>>> (B, 1)
>>>>> (B, 2)
>>>>> (C, 5)
>>>>> (D, 6)
>>>>> (D, 7)
>>>>> (E, 8)
>>>>> (F, 8)
>>>>>
>>>>> For journalling, I need to group/cluster this together. Is there a SQL
>>>>> query that can generate this output:
>>>>>
>>>>> # (journal: invoiceids, txids)
>>>>> [A,B] , [1,2,3]
>>>>> [C], [5]
>>>>> [D], [6,7]
>>>>> [E,F], [8]
>>>>
>>>> Hi Dave,
>>>>
>>>> I'm not following the logic here. A has 1,3 and B has 1,2. So why does
>>>> the first line print:
>>>>
>>>>> [A,B] , [1,2,3]
>>>>
>>>> What's the rule that tells the query to output this way? Is it that all
>>>> of B's values are between A's values?
>>>
>>> From a purely accounting standpoint, since transaction 1 was applied to
>>> both invoices A and B, you need to group the invoices so that you can
>>> compare total invoiced against total paid.
>>
>> I tinkered around briefly but didn't come up with a good idea, but I bet
>> someone on this list can. However, I did create a CREATE script for your
>> table design which, in my experience, makes it more likely that a real
>> expert will take on your problem..
>>
>> Hope this helps,
>>
>> Steve
>>
>> DROP TABLE IF EXISTS trans;
>>
>> CREATE TABLE trans
>> (
>> id serial NOT NULL,
>> inv_id character varying,
>> tx_id character varying,
>> CONSTRAINT pk_id PRIMARY KEY (id)
>> )
>> WITH (OIDS=FALSE);
>>
>> insert into trans (inv_id, tx_id) values('A','1');
>> insert into trans (inv_id, tx_id) values('A','3');
>> insert into trans (inv_id, tx_id) values('B','1');
>> insert into trans (inv_id, tx_id) values('B','2');
>> insert into trans (inv_id, tx_id) values('C','5');
>> insert into trans (inv_id, tx_id) values('D','6');
>> insert into trans (inv_id, tx_id) values('D','7');
>> insert into trans (inv_id, tx_id) values('E','8');
>> insert into trans (inv_id, tx_id) values('F','8');
Here's a stab at a custom aggregate attempting to explain what's going
on inside.
CREATE OR REPLACE FUNCTION varchar_array_accum_unique (x VARCHAR[], y
VARCHAR) RETURNS VARCHAR[] AS $$
DECLARE
res VARCHAR[];
BEGIN
RAISE NOTICE 'input state is %',x;
RAISE NOTICE 'input variable is %',y;
IF x = '{}' THEN
RAISE NOTICE 'x is empty, returning input variable %',y;
res[1] := y;
ELSE
RAISE NOTICE 'input array is not empty, checking if input
variable is a member %',y;
res := x;
IF y = ANY(res) THEN
RAISE NOTICE 'y is already in array %, skipping',res;
ELSE
res := array_append(res, y);
RAISE NOTICE 'appending input variable %',y;
END IF;
END IF;
RETURN res;
END
$$ LANGUAGE plpgsql STRICT;
DROP AGGREGATE array_accum_unique(VARCHAR);
CREATE AGGREGATE array_accum_unique
(
basetype = VARCHAR
, sfunc = varchar_array_accum_unique
, stype = VARCHAR[]
, initcond = '{}'
);
SELECT array_accum_unique(inv_id) AS invoiceids
, array_accum_unique(tx_id) AS transactionids
FROM (
SELECT tx_id, inv_id
FROM trans
WHERE inv_id IN (
SELECT inv_id
FROM trans
WHERE id IN (
SELECT id FROM trans
WHERE tx_id=1
)
)
ORDER BY tx_id, inv_id
) AS ss
;
Returns this result for transaction id 1.
invoiceids | transactionids
+
{A,B} | {1,2,3}
(1 row)
Hope this helps!
Tony
--
Sent via pgsql-sql mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-sql
