Re: [SQL] find all tables with a specific column name?

2006-04-22 Thread Ben K.

Is there a reasonable way to extract a list of all tables which contain a
specific column name from the system views on 8.1?
For instance, I might want to enumerate all tables with a column named
last_modified.


This is nothing new but if I may, may I add for this thread's completeness 
a try from internal tables?


select a.relkind, a.relname from pg_class a inner join pg_attribute b on 
a.relfilenode = b.attrelid group by a.relkind, a.relname, 
a.relfilenode,b.attname having b.attname='IID';


The result didn't match the one from the information_schema.tables - the 
above query included indexes too (relkind=i) while 
information_schema.tables included only tables and views (r,v).



Ben K.
Developer
http://benix.tamu.edu

---(end of broadcast)---
TIP 5: don't forget to increase your free space map settings


Re: [SQL] LinkedList

2006-04-27 Thread Ben K.

I have a table that I created that implements a linked list.  I am not an
expert SQL developer and was wondering if there are known ways to traverse
the linked lists.  Any information that can point me in the direction to
figure this out would be appreciated.  The table contains many linked lists
based upon the head of the list and I need to extract all of the nodes that
make up a list.  The lists are simple with a item and a link to the history
item so it goes kind of like:


It may not be exactly suitable, but this one does only traversal (assuming 
the list is not clsoed)


create table linkedlist(prevnode int, nextnode int, val int);
-- HEAD
insert into linkedlist values(null,1,0);
insert into linkedlist values(1,2,10);
insert into linkedlist values(2,3,20);
insert into linkedlist values(3,4,30);
insert into linkedlist values(4,5,40);
-- TAIL
insert into linkedlist values(5,null,50);

-- TRAVERSE
begin;
declare mc cursor for select * from linkedlist order by nextnode;
fetch 1 from mc;
fetch 1 from mc;
...
close mc;
commit;

which is nothing more than,
select * from linkedlist order by nextnode;


Regards,

Ben K.
Developer
http://benix.tamu.edu

---(end of broadcast)---
TIP 3: Have you checked our extensive FAQ?

  http://www.postgresql.org/docs/faq


Re: [SQL] LinkedList

2006-04-28 Thread Ben K.

On Fri, 28 Apr 2006, Guy Fraser wrote:


-- HEAD
insert into linkedlist values(null,1,0);
insert into linkedlist values(1,2,10);
insert into linkedlist values(2,3,20);
insert into linkedlist values(3,4,30);
insert into linkedlist values(4,5,40);
-- TAIL
insert into linkedlist values(5,null,50);





Bad example of a double linked list, you also need an id for
the current node and the values of prevnode and nextnode do not
need to be ordered or contiguous as the example shows.




Wow. Interesting... I am willing to be corrected, but to me the "node" 
field seems redundant, since it does not add any information. (Since each 
item in the list is already uniquely identifiable without the "node".) 
Certainly so, for traversing, which was the OP's intention.


It may save some steps in case of other operations but at the expense of 
one more field. Please see below.





create table linkedlist(node int,prevnode int, nextnode int, val int);
insert into linkedlist values(1,null,2,0);
insert into linkedlist values(2,1,3,10);
insert into linkedlist values(3,2,4,30);
insert into linkedlist values(4,3,5,20);
insert into linkedlist values(5,4,6,40);
insert into linkedlist values(6,5,null,50);



If we now wanted to reorder an item in the set you need
make some updates in a block, which I have not done before
but should be something like this:

Move node 4 between 2 and 3 so that the values from head
to tail are ordered.

update linkedlist set prevnode = '2',nextnode = '3' where node = '4';
update linkedlist set nextnode = '4' where node = '2';
update linkedlist set prevnode = '4' where node = '3';




If the intention is to change it from 0-10-30-20-40-50 to 
0-10-20-30-40-50, it would have been (in my design) exchanging node 3 and 
node 4 below.


null,1,0
1,2,10  <-- node 2
2,3,30  <-- node 3
3,4,20  <-- node 4
4,5,40
5,null,50

Now, it can be done by:

begin;
update linkedlist set prevnode=2 where prevnode=3; -- node 4 = (2,4,20)
update linkedlist set prevnode=3 where nextnode=3; -- node 3 = (3,3,30)
update linkedlist set nextnode=3 where prevnode=2; -- node 4 = (2,3,20)
update linkedlist set nextnode=4 where nextnode=3; -- node 3 = (3,4,30)
commit;

achieving the same.
...
2,3,20  <-- node 4, originally
3,4,30  <-- node 3, originally
...

"node" will be more cost efficient if we insert an item at the beginning 
of a long list, for example insert

(2,3,100)
before node 3 (2,3,20), but at least the sql is simple;

update linkedlist set prevnode = prevnode + 1 where prevnode > 1;
update linkedlist set nextnode = nextnode + 1 where nextnode > 2;
and then do insert (2,3,xxx)

This method can also be used for reordering.

The usefulness of the "node" will depend on the economics of these update 
operations over keeping one more field.


But I think this is more of an exercise, and functions would be the proper 
way for complex operations.



Regards,

Ben K.
Developer
http://benix.tamu.edu

---(end of broadcast)---
TIP 4: Have you searched our list archives?

  http://archives.postgresql.org


Re: [SQL]Linked List

2006-04-30 Thread Ben K.

I have a table that I created that implements a linked list.  I am not an
expert SQL developer and was wondering if there are known ways to traverse
the linked lists.  The table contains many linked lists based upon the head
of the list and I need to extract all of the nodes that make up a list.  The
lists are simple with a item and a link to the history item so it goes kind
of like:

1, 0
3, 1
7, 3
9, 7
...


I missed "The table contains many linked lists", so wanted to do another 
try. I guess there should be a better way, but what if you do this?


1)

Assuming your table has two columns (n int, p int), do

create table tmplist (n int, p int);

2)

drop function traverse(integer);
create or replace function traverse (integer)
returns integer as
$$
  declare
x int;
  begin
x := $1;
while x is not null loop
  select n into x from linkedlist where p = x;
  insert into tmplist (select * from links where p=x);
-- or do any processing
end loop;
return 1 ;
  end;
$$
language plpgsql;

3)

select traverse(0);
select * from tmplist;
0 - 1 - 4 - 8 - 12 ...


delete from tmplist;
select traverse(2);
select * from tmplist;
2 - 3 - 5 - 6 - ...

(where 0 or 2 is the heads of the linked lists in the table, which you 
want to traverse)


I'd appreciate any insight if there's a better way but somehow it was not 
possible to return setof int from within while loop whereas it was 
possible from within a for loop. I didn't find a way to deliver the 
templist table name as argument. (Somehow there seemed to be a bug(?) 
there)




Regards,

Ben K.
Developer
http://benix.tamu.edu

---(end of broadcast)---
TIP 3: Have you checked our extensive FAQ?

  http://www.postgresql.org/docs/faq


Re: [SQL]Linked List

2006-04-30 Thread Ben K.
The pgsql function is compiled and wouldn't know how to handle a table 
name as a variable.


If you rewrite the SQL to use the 'EXECUTE' statement I think you could 
do this, something along the lines of (untested):


EXECUTE ''INSERT INTO '' || quote_ident(tmplist) || '' (SELECT * FROM 
links WHERE p=x)'';


Thanks. Yet, if I give the table name as the argument, I get the same 
error.


drop function traverse(integer, text);
create or replace function traverse (integer, text)
returns integer as
$$
  declare
x int;
tname alias for $2;
  begin
x := $1;
while x is not null loop
  select n into x from links where p = x;
  insert into tmplink (select * from links where p=x);
  EXECUTE ''INSERT INTO '' || quote_ident(tname) || '' (SELECT * FROM
links WHERE  p=x)'';
end loop;
return 1 ;
  end;
$$
language plpgsql;

The above gives the following error. Please note that the first and 
second args are mixed up now. I tested it only on 8.0 (FC 4) and didn't on 
8.1 and wonder whether it's a bug or I may be doing something wrong.


Using tname or $2 doesn't change the result.



# select traverse(0, 'links2');
ERROR:  syntax error at or near "INSERT" at character 11
QUERY:  SELECT  ''INSERT INTO '' || quote_ident( $1 ) || '' (SELECT * FROM 
links WHERE p= $2 )''

CONTEXT:  PL/pgSQL function "traverse" line 10 at execute statement
LINE 1: SELECT  ''INSERT INTO '' || quote_ident( $1 ) || '' (SELECT ...



Regards,

Ben K.
Developer
http://benix.tamu.edu

---(end of broadcast)---
TIP 5: don't forget to increase your free space map settings


Re: [SQL] Sorting aggregate column contents

2006-05-02 Thread Ben K.

It works fine. But I wouldn't like using subselect's, then if somebody else
knows about an operator or something like that to put on the aggregator, 
please tell me.



I think the nature of the f_concat makes it difficult to sort, since it 
simply adds the next value, so if the source table gives value in the 
order of 'a','c','d','b' there's no way to handle them within f_concat 
unless you modify and rearrange the previous result string from within 
f_concat.



So the source table (city) should be sorted. I don't know if this is a 
standard way, but this one seems to do that.



==
select s.name, ag_concat(c.name) from state s inner join (select * from 
city order by name desc) as c on c.idstate=s.idstate group by s.name order by 1;


OR

select s.name, ag_concat(c.name) from state s, (select * from city order 
by name desc) as c where c.idstate = s.idstate group by s.name order by 1;

==


I'm just reordering the source table on the fly. Curiously, if you don't 
have 'desc' you'll get a reverse ordered list. (z,...,a)


I think your needs may also be met without any aggregator as well (there 
may be marginal cases which I haven't thought of, but I assume they can be 
handled if needed)


==
select s.name, array_to_string(array(select name from city where 
idstate = s.idstate order by name),',') from state s;

==

  name |   array_to_string
--+-
  RP   | Gramado,Port Alegre
  SP   | Osasco


* I see normalization issue here but guess it's not important.



Regards,

Ben K.
Developer
http://benix.tamu.edu

---(end of broadcast)---
TIP 5: don't forget to increase your free space map settings


Re: [SQL] LinkedList

2006-05-02 Thread Ben K.

The problem is that your way, there is no indicated way to determine
which node is which. For instance is you update any of your nodes
then the node list would be out of order and your list would not
work.


I think the thinking is different here. The OP's list is ordered and has 
prev-next only, and there can be lists that are read only and/or ordered 
(like clickstream or a data stream out of multi-stream packets) and do not 
require insert. That's why I mentioned it's for traverse-only in my 
original post.


(But I disagree with you about not being able to determine a node - since 
in sql it's possible to identify a row as long as it has unique values in 
fields, however they are named)



After I posted the message I realized there is another way to
do this without adding an extra field, and it would be a closer
example to how it is done in C. If you assigned the OID of the
previous and next nodes rather than arbitrary integer, you could
access each node independent of the order they are listed.

I have not messed around much with OIDs. I am not sure if
OIDs change if an entry is updated.


I understand oid doesn't change with update. But tables may or may not 
have oids. (can be created "without oids") I also came to appreciate the 
difference with C.


In sql, there is a way to identify a row like I did, but in C it'd not be 
possible without the address (of course it's not like "impossible" but 
...), so the linked list as in strict C-like sense would be perfect but 
may carry a different value here. (Since we already have the added layer 
of sql engines.) I agree your method would be better if we want to scale 
when insert or delete is needed.


It'd be interesting to compare how the normal O() applies to sql - would 
updating n rows with one sql statement be equivalent to O(n) in C? Maybe a 
silly question but it came to my mind...



In C you would use a pointer to storage location of previous
and next "node" which is similar to using the OID. In some
cases it can be necessary to use pointers to pointers when
accessing variable length relocatable data, but that goes way
past what this thread is about.
The example I provided, is still feasible and alleviates all
unknowns at the expense of 4 bytes of storage for one integer
used as a fixed address for each node.



As long as it works in real world use. Without some way of addressing
each node, the idea of a linked list seems wrong, since a linked is
supposed to hold the address of the previous and or next item in the
list, assuming the data is always going to be correctly sorted so that
you can locate the next item by tupple number seems overly assumptive.
If it works for you great, your example may then be useful as a short
cut, but I don't believe in leaving things to chance when programming.





Regards,

Ben K.
Developer
http://benix.tamu.edu

---(end of broadcast)---
TIP 9: In versions below 8.0, the planner will ignore your desire to
  choose an index scan if your joining column's datatypes do not
  match


Re: [SQL] i am getting error when i am using copy command

2006-05-03 Thread Ben K.

file '/tmp/penchal.out'  for writing: no such file or directory..


_IF_ you're on linux it could be due to selinux. setenforce 0 might solve 
the problem tempoarily. I would assume there should've been some existing 
discussion threads. (setenforce 1 afterwards.)


Regards,

Ben K.

---(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] audit table containing Select statements submitted

2006-05-04 Thread Ben K.

Current_user
Timestamp
"The Select Statement Submitted by the User"


http://www.postgresql.org/docs/8.1/static/plpgsql-trigger.html#PLPGSQL-TRIGGER-AUDIT-EXAMPLE

might be close to what you want.


Regards,

Ben K.
Developer
http://benix.tamu.edu

---(end of broadcast)---
TIP 3: Have you checked our extensive FAQ?

  http://www.postgresql.org/docs/faq


Re: [SQL] Returning String as Integer

2006-05-06 Thread Ben K.

Jorge Godoy <[EMAIL PROTECTED]> wrote:

numbers. Is there any way to select a value from this column and return
it as an integer?


My twopence. I just happened to have the same problem with iReports for a 
10 digit number - it may be case specific but in my case


# select ... int4(id) ...;

worked.

I tried int8(id) but java didn't take it as Integer. (It took int8 as 
something like Long.)



Regards,

Ben

---(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] Returning String as Integer

2006-05-06 Thread Ben K.

My twopence. I just happened to have the same problem with iReports for a
10 digit number - it may be case specific but in my case


Please, take care with your quote attributions.  I've never asked such a
question here and, in fact, I was answering it.  The person who asked such a
question was Kashmira Patel.


Sorry, I apologize.

Regards,

Ben K.

---(end of broadcast)---
TIP 3: Have you checked our extensive FAQ?

  http://www.postgresql.org/docs/faq


Re: [SQL] Most efficient way to hard-sort records

2006-05-06 Thread Ben K.

main_table: id, name, position
key_table: id, main_table_id, key, value

Here is how I need to sort the records:
SELECT * FROM main_table
INNER JOIN key_table ON main_table.id = key_table.main_table_id
WHERE key = 'param'
ORDER BY value

I currently collect all ids from main_table in sorted order and then
update the position field for each row in the main_table one-by-one. Is
there a better/faster/more efficient solution?



A cheap solution if you don't care about the position value as long as 
sort order is ok.


1)
# SELECT main_table.id into temp_table FROM main_table INNER JOIN 
key_table ON main_table.id = key_table.main_table_id ORDER BY value;


2)
# update main_table set position = (select oid from temp_table where id = 
main_table.id );


I guess I'll get a set of consecutive oids by this.

You can make the number begin at arbitrary number, by

2-a)
# update main_table set position = ( (select oid::int4 from temp_table 
where id = main_table.id ) - (select min(oid::int4) from temp_table) + 1) 
;


I read that oid wraps around (after ~ billions) so you might want to check 
your current oid.





Regards,

Ben K.
Developer
http://benix.tamu.edu

---(end of broadcast)---
TIP 5: don't forget to increase your free space map settings


Re: [SQL] Most efficient way to hard-sort records

2006-05-07 Thread Ben K.

CREATE TABLE sorted (order_no SERIAL PRIMARY KEY, other columns...)
	INSERT INTO sorted (columns) SELECT * FROM main_table INNER JOIN 
key_table ON main_table.id = key_table.main_table_id WHERE key = 'param' ORDER 
BY value SELECT
	The SERIAL will automatically generate the order_no you want, which 
corresponds to the position in the sorted set.

Then, to get the records in-order :
SELECT * FROM sorted ORDER BY order_no


Good ... I just got myself into the habit of not recreating a table since 
I have to clean up permissions and what not. I guess it depends.


Another version along that line ?

# create sequence counterseq start 1;
-- (set/reset whenever a counter is needed)

# select main_table.*, nextval('counterseq') as position2
  into sorted_main_table
  from main_table, keytable where main_table.id =
  keytable.main_table_id
  order by value;




Regards,

Ben K.
Developer
http://benix.tamu.edu

---(end of broadcast)---
TIP 4: Have you searched our list archives?

  http://archives.postgresql.org


Re: [SQL] keeping last 30 entries of a log table

2006-06-21 Thread Ben K.
I need to write a function which inserts a log entry in a log table and only 
keeps the last 30 records.  I was thinking of using a subquery similar to the 
following:


insert into log (account_id, message) values (1, 'this is a test);
delete from log where account_id = 1 and id not in ( select id from log
 where account_id = 1 order by timestamp desc limit 30);

I'm wondering if there is a more performance oriented method of doing the 
delete that I'm not thinking of.



Just for the sake of alternatives -

create sequence cy30 maxvalue 30 cycle;

insert into log values(select generate_series(1,30), 'dummy');
INSERT 0 30

update log set des='' where account_id=(select nextval('cy30'));
UPDATE 1


There are details to consider I guess. For example what if an update fails 
and the sequence already advanced... Also, since we cycle the id, for 
sorting, we'll need to add timestamp or something similar.


My 2 pence...

P.S.

This A) failed me and I wonder if this is supposed to be so or if it's 
just a place where no one treaded on ??


B) works fine except it doesn't advance the sequence.

A) update  tc set des='b' where id=nextval('cy30')::int;
UPDATE 30

B) update tc set des='c' where id=currval('cy30');
UPDATE 1


Regards,

Ben K.
Developer
http://benix.tamu.edu

---(end of broadcast)---
TIP 3: Have you checked our extensive FAQ?

  http://www.postgresql.org/docs/faq