Re: [SQL] Interval subtracting

2006-02-20 Thread Milorad Poluga
Thank you all for suggestions and links. 
Currently, I am working on  PostgreSQL 8.0.4., so I cannot use justify_*() 
functions.

Regards, 
Milorad Poluga

[EMAIL PROTECTED]

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

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


Re: [SQL] SELECT on a to-be-determined table

2006-02-20 Thread Patrick JACQUOT

garhone wrote:


Hi,

I'm a new at this. So please forgive if I mess up. Also, if there is
already a reference/tutorial somewhere, feel free to point me to it.

Here's my situation:
db=# select * from projects;
projid | projname
+--
 1 | cars
 2 | houses
 3 | pets
(3 rows)

db=# select * from cars;
carid | carname
---+-
1 | ford
2 | mazda
(2 rows)

db=# select * from houses;
houseid | housename
-+---
  1 | semi
  2 | trailer
  3 | mansion
(3 rows)

db=# select * from pets;
petid | petname
---+-
1 | dog
2 | cat
3 | bird
(3 rows)

Is it possible to do this:
Give me all the rows of the table whose project id is 2 (or whatever
projid).

Thanks


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

  http://archives.postgresql.org



Your way of thinking leads to the need of comparing a field to a table name.
Such a request requires two steps
1 - retrieve the name of the table to search in, store it in a variable
2 - use execute to issue a request to that table.

Instead, I think it would be better to use only two tables:
1 - projects (projid, projname)
2 - items (itemid, projid, itemproperty1,itemidproperty2,...)
You would have in the second table, to take your example:
projid | itemid | itemname   |
1 |  1 | ford   |
1 |  2 | mazda  |
2 |  1 | semi   |
2 |  2 | trailer|
2 |  3 | mansion|
3 |  1 | dog|
3 |  2 | cat|
3 |  3 | bird   |
Your request would become :
SELECT itemid, itemname FROM items where projid=2

The problem of having a different set of properties
for the items of differents projects could be solved with three tables:
project(projid, projname)
itempropertymeaning(projid, propid, propmeaning)
itemproperty(projid, itemid, propid, propvalue)

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


Re: [SQL] Need help: Find dirty rows, Update, Delete SQL

2006-02-20 Thread Patrick JACQUOT

Janning Vygen wrote:


Am Samstag, 18. Februar 2006 18:41 schrieb [EMAIL PROTECTED]:
 


Hello,

I need a bit of help with some SQL.
I have two tables, call them Page and Bookmark.
Each row in Page can have many Bookmarks pointing to it, and
they are joined via a FK (Page.id = Bookmark.page_id).

Page has a 'url' column: Page.url, which has a unique index on it.

My Page.url column got a little dirty, and I need to clean it up,
and that's what I need help with.

Here is an example of dirtiness:

Page:

id=1 url = 'http://example.com/'
id=2 url = 'http://example.com/#' -- dirty
id=3 url = 'http://example.com/#foo'  -- dirty

The last two rows are dirty.  Normally I normalize URLs before
inserting them, but these got in, and now I need to clean them.

The problem is that rows in Bookmark table may point to dirty
rows in Page, so I can't just remove the dirty rows, and I can't
just update 'url' column in Page to 'http://example.com/',
because that column is unique.

Is there some fancy SQL that I can use them to find the dirty
rows in page (... where url like '%#%') and then find rows in
Bookmark table that point to them, then point those rows to
good rows in Page (e.g. id=1 row above), and finally remove the
dirty rows from Page?
   



try this. But please check if it really does its job. I just wrote it down in 
a minute or two. There will be an easier way or nicer written SQL but a sit 
is just a one time operation you shoudn't care too much. One more hint: you 
should add a CHECK clause to your page_url like  "page_url text NOT NULL 
UNIQUE CHECK (page_url !~ '#')"


here is my test code

CREATE TABLE pages (
 page_id SERIAL PRIMARY KEY,
 page_url text NOT NULL UNIQUE
);

CREATE TABLE bookmarks (
 bm_id SERIAL PRIMARY KEY,
 bm_text text not null,
 page_id int4 NOT NULL REFERENCES pages (page_id)
);

INSERT INTO pages (page_url) VALUES ('http://example.com/');
INSERT INTO pages (page_url) VALUES ('http://example.com/#');
INSERT INTO pages (page_url) VALUES ('http://example.com/#foo');
INSERT INTO pages (page_url) VALUES ('http://example2.com/#foo');
INSERT INTO pages (page_url) VALUES ('http://example3.com/#foobar');

insert into bookmarks (bm_text, page_id) values ('test1', 1);
insert into bookmarks (bm_text, page_id) values ('test2', 1);
insert into bookmarks (bm_text, page_id) values ('test3', 2);
insert into bookmarks (bm_text, page_id) values ('test4', 2);
insert into bookmarks (bm_text, page_id) values ('test5', 3);
insert into bookmarks (bm_text, page_id) values ('test6', 3);
insert into bookmarks (bm_text, page_id) values ('test7', 4);

BEGIN;
UPDATE bookmarks set page_id = pages2.page_id
FROM 
 pages AS pages1, 
 pages AS pages2
WHERE 
 pages1.page_id = bookmarks.page_id

 AND pages2.page_url = split_part(pages1.page_url, '#', 1)
;

DELETE FROM pages WHERE page_id IN (
 SELECT 
   pages1.page_id

 FROM
   pages AS pages1 
   JOIN pages AS pages2 ON ( 
 pages1.page_id != pages2.page_id 
 AND pages2.page_url = split_part(pages1.page_url, '#', 1)

   )
 WHERE position('#' in pages1.page_url) > 0
 AND pages1.page_id NOT IN (SELECT page_id FROM bookmarks)
);
;

UPDATE pages SET page_url = split_part(page_url, '#', 1) 
WHERE position('#' in pages.page_url) > 0

;
select * from bookmarks;
select * from pages;
COMMIT;


kind regards,
janning

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

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

 

why do you consider as dirty perfectly honest URLs as 
http://example.com#foo ?
Such a construct points to a specific part (foo) of a specific document 
(http://example.com)



---(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] ORDER BY CASE ...

2006-02-20 Thread Bruno Wolff III
On Mon, Feb 13, 2006 at 22:28:38 +0100,
  Mario Splivalo <[EMAIL PROTECTED]> wrote:
> Can't do so, because receiving_time is timestamptz, and "from" is
> varchar. There:
> 
> pulitzer2=# select id, "from", receiving_time from messages order by
> case when 2=3 then "from" else receiving_time end desc limit 5;
> ERROR:  CASE types timestamp with time zone and character varying cannot
> be matched
> 
> I need to explicitly cast receiving_time into varchar.
> 
> What I would like to include ASC/DESC into CASE, but I guess that's not
> possible.

If you describe what order you are trying to get we might be able to give
you a more specific suggestion.

It looks like you are trying to sort on different column numbers based
on whether or not two other column numbers (that weren't shown) are equal.
(The syntax you are using for doing this isn't correct, but it is the only
thing that seems to make sense.)

Since columns 2 and 3 aren't really comparable, how were you expecting
the rows for the two cases to be interspersed? Just converting a timestamp
to a string seem like it wouldn't be the right answer.

---(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] Given 02-01-2006 to 02-28-2006, output all days.

2006-02-20 Thread Pedro B.
Hello.
I'm having difficulties on my first incursion through generate_series.

The details:

SELECT DATE_TRUNC('month', timestamp '2006-02-01' )::DATE + s.d AS date,
      COUNT (o."04-sms") as totalcause98
      FROM generate_series(11,19) AS s(d)
 LEFT JOIN netopia o ON (substr(o."26-insertTime",1,10) = (DATE_TRUNC('month', 
timestamp'2006-02-01'  )::DATE + s.d) and o.cause01=98)
 GROUP BY s.d ORDER BY 1;


This query (although quite messed up on the date parameters), does exactly 
what i want: 
"sum column 'cause01=98' for a specified date range, including 0's"

date| totalcause98
+--
 2006-02-12 |0
 2006-02-13 |0
 2006-02-14 |0
 2006-02-15 |0
 2006-02-16 |   68
 2006-02-17 |  256
 2006-02-18 |  104
 2006-02-19 |   34
 2006-02-20 |   20

I'm using a left join because i really need the =0 sums.
The use of substr() is due to the fact the "26-insertTime" on the 'netopia' 
table has a default of 'default (now())::timestamp(2) without time zone'.
So, i can make generate_series work with the left join using the substr.
I was getting ready to optimize this query, when i remembered i also have the 
need for another column, 'totalcause99', almost the same as this query, but 
with 'cause01=99' as condition.

The maximum i was able to do without syntax errors was:

SELECT DATE_TRUNC('month', timestamp '2006-02-01' )::DATE + s.d AS date,
      COUNT (o."04-sms") as totalcause98,
      COUNT (p."04-sms") as totalcause99
      FROM generate_series(11,19) AS s(d)
 LEFT JOIN netopia o ON (substr(o."26-insertTime",1,10) = (DATE_TRUNC('month', 
timestamp'2006-02-01'  )::DATE + s.d) and o.cause01=98)
 LEFT JOIN netopia p ON (substr(p."26-insertTime",1,10) = (DATE_TRUNC('month', 
timestamp'2006-02-01'  )::DATE + s.d) and p.cause01=99)
 GROUP BY s.d ORDER BY 1;

Reading this one aloud, i feel the "logic" of what i'm trying to do, but the 
values of its output are.. scary to say the least, and the sums are exactly 
the same on the 2 columns, and that should never happen with the data i have 
on the table.

I'm starting to wonder if this is actually possible to be done on one single 
query...
Ideas, anyone?

Sorry for the long email.
Any and all help is deeply appreciated.

Regards,

-- 
\\pb

---(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] Given 02-01-2006 to 02-28-2006, output all days.

2006-02-20 Thread Mark R. Dingee
Pedro,

Would something such as this suffice?

Mark 

create function get_date_range(date, date) returns setof date as '
DECLARE
    cur date;
BEGIN
    cur := $1;

    while cur <= $2 LOOP
         return next cur;
         cur := cur + interval ''1 day'';
    end LOOP;
    return;
END;' language 'plpgsql';

dev=# select * from get_date_range('2/1/2006'::date, '2/28/2006'::date);
 get_date_range

 2006-02-01
 2006-02-02
 2006-02-03
 2006-02-04
 2006-02-05
 2006-02-06
 2006-02-07
 2006-02-08
 2006-02-09
 2006-02-10
 2006-02-11
 2006-02-12
 2006-02-13
 2006-02-14
 2006-02-15
 2006-02-16
 2006-02-17
 2006-02-18
 2006-02-19
 2006-02-20
 2006-02-21
 2006-02-22
 2006-02-23
 2006-02-24
 2006-02-25
 2006-02-26
 2006-02-27
 2006-02-28
(28 rows)

On Monday 20 February 2006 15:30, Pedro B. wrote:
> Hello.
> I'm having difficulties on my first incursion through generate_series.
>
> The details:
>
> SELECT DATE_TRUNC('month', timestamp '2006-02-01' )::DATE + s.d AS date,
>       COUNT (o."04-sms") as totalcause98
>       FROM generate_series(11,19) AS s(d)
>  LEFT JOIN netopia o ON (substr(o."26-insertTime",1,10) =
> (DATE_TRUNC('month', timestamp'2006-02-01'  )::DATE + s.d) andcreate 
function get_date_range(date, date) returns setof date as '
DECLARE
cur date;
BEGIN
cur := $1;

while cur <= $2 LOOP
 return next cur;
 cur := cur + interval ''1 day'';
end LOOP;
return;
END;' language 'plpgsql';

dev=# select * from get_date_range('2/1/2006'::date, '2/28/2006'::date);
 get_date_range

 2006-02-01
 2006-02-02
 2006-02-03
 2006-02-04
 2006-02-05
 2006-02-06
 2006-02-07
 2006-02-08
 2006-02-09
 2006-02-10
 2006-02-11
 2006-02-12
 2006-02-13
 2006-02-14
 2006-02-15
 2006-02-16
 2006-02-17
 2006-02-18
 2006-02-19
 2006-02-20
 2006-02-21
 2006-02-22
 2006-02-23
 2006-02-24
 2006-02-25
 2006-02-26
 2006-02-27
 2006-02-28
(28 rows)
> o.cause01=98)
>  GROUP BY s.d ORDER BY 1;
>
>
> This query (although quite messed up on the date parameters), does exactly
> what i want:
> "sum column 'cause01=98' for a specified date range, including 0's"
>
> date| totalcause98
> +--
>  2006-02-12 |0
>  2006-02-13 |0
>  2006-02-14 |0
>  2006-02-15 |0
>  2006-02-16 |   68
>  2006-02-17 |  256
>  2006-02-18 |  104
>  2006-02-19 |   34
>  2006-02-20 |   20
>
> I'm using a left join because i really need the =0 sums.
> The use of substr() is due to the fact the "26-insertTime" on the 'netopia'
> table has a default of 'default (now())::timestamp(2) without time zone'.
> So, i can make generate_series work with the left join using the substr.
> I was getting ready to optimize this query, when i remembered i also have
> the need for another column, 'totalcause99', almost the same as this query,
> but with 'cause01=99' as condition.
>
> The maximum i was able to do without syntax errors was:
>
> SELECT DATE_TRUNC('month', timestamp '2006-02-01' )::DATE + s.d AS date,
>       COUNT (o."04-sms") as totalcause98,
>       COUNT (p."04-sms") as totalcause99
>       FROM generate_series(11,19) AS s(d)
>  LEFT JOIN netopia o ON (substr(o."26-insertTime",1,10) =
> (DATE_TRUNC('month', timestamp'2006-02-01'  )::DATE + s.d) and
> o.cause01=98)
>  LEFT JOIN netopia p ON (substr(p."26-insertTime",1,10) =
> (DATE_TRUNC('month', timestamp'2006-02-01'  )::DATE + s.d) and
> p.cause01=99)
>  GROUP BY s.d ORDER BY 1;
>
> Reading this one aloud, i feel the "logic" of what i'm trying to do, but
> the values of its output are.. scary to say the least, and the sums are
> exactly the same on the 2 columns, and that should never happen with the
> data i have on the table.
>
> I'm starting to wonder if this is actually possible to be done on one
> single query...
> Ideas, anyone?
>
> Sorry for the long email.
> Any and all help is deeply appreciated.
>
> Regards,

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


Re: [SQL] ... more than one count with left join

2006-02-20 Thread Pedro B.
On Monday 20 February 2006 20:39, Mark R. Dingee Pedro wrote:
|>  Pedro,
|>
|>  Would something such as this suffice?

Hello Mark,

It's far superior to what i was doing, serialization wise. Thank you.

However, it still leaves me with the big headache of the left joins with the 
"count ... where..."...


Thanks,
\\pb

|>
|>  Mark
|>
|>  create function get_date_range(date, date) returns setof date as '
|>  DECLARE
|>      cur date;
|>  BEGIN
|>      cur := $1;
|>
|>      while cur <= $2 LOOP
|>           return next cur;
|>           cur := cur + interval ''1 day'';
|>      end LOOP;
|>      return;
|>  END;' language 'plpgsql';
|>
|>  dev=# select * from get_date_range('2/1/2006'::date, '2/28/2006'::date);
|>   get_date_range
|>  
|>   2006-02-01
|>   2006-02-02
|>   2006-02-03
|>   2006-02-04
|>   2006-02-05
|>   2006-02-06
|>   2006-02-07
|>   2006-02-08
|>   2006-02-09
|>   2006-02-10
|>   2006-02-11
|>   2006-02-12
|>   2006-02-13
|>   2006-02-14
|>   2006-02-15
|>   2006-02-16
|>   2006-02-17
|>   2006-02-18
|>   2006-02-19
|>   2006-02-20
|>   2006-02-21
|>   2006-02-22
|>   2006-02-23
|>   2006-02-24
|>   2006-02-25
|>   2006-02-26
|>   2006-02-27
|>   2006-02-28
|>  (28 rows)
|>
|>  On Monday 20 February 2006 15:30, Pedro B. wrote:
|>  > Hello.
|>  > I'm having difficulties on my first incursion through generate_series.
|>  >
|>  > The details:
|>  >
|>  > SELECT DATE_TRUNC('month', timestamp '2006-02-01' )::DATE + s.d AS
|>  > date, COUNT (o."04-sms") as totalcause98
|>  >       FROM generate_series(11,19) AS s(d)
|>  >  LEFT JOIN netopia o ON (substr(o."26-insertTime",1,10) =
|>  > (DATE_TRUNC('month', timestamp'2006-02-01'  )::DATE + s.d) andcreate
|>
|>  function get_date_range(date, date) returns setof date as '
|>  DECLARE
|>      cur date;
|>  BEGIN
|>      cur := $1;
|>
|>      while cur <= $2 LOOP
|>           return next cur;
|>           cur := cur + interval ''1 day'';
|>      end LOOP;
|>      return;
|>  END;' language 'plpgsql';
|>
|>  dev=# select * from get_date_range('2/1/2006'::date, '2/28/2006'::date);
|>   get_date_range
|>  
|>   2006-02-01
|>   2006-02-02
|>   2006-02-03
|>   2006-02-04
|>   2006-02-05
|>   2006-02-06
|>   2006-02-07
|>   2006-02-08
|>   2006-02-09
|>   2006-02-10
|>   2006-02-11
|>   2006-02-12
|>   2006-02-13
|>   2006-02-14
|>   2006-02-15
|>   2006-02-16
|>   2006-02-17
|>   2006-02-18
|>   2006-02-19
|>   2006-02-20
|>   2006-02-21
|>   2006-02-22
|>   2006-02-23
|>   2006-02-24
|>   2006-02-25
|>   2006-02-26
|>   2006-02-27
|>   2006-02-28
|>  (28 rows)
|>
|>  > o.cause01=98)
|>  >  GROUP BY s.d ORDER BY 1;
|>  >
|>  >
|>  > This query (although quite messed up on the date parameters), does
|>  > exactly what i want:
|>  > "sum column 'cause01=98' for a specified date range, including 0's"
|>  >
|>  >     date    | totalcause98
|>  > +--
|>  >  2006-02-12 |            0
|>  >  2006-02-13 |            0
|>  >  2006-02-14 |            0
|>  >  2006-02-15 |            0
|>  >  2006-02-16 |           68
|>  >  2006-02-17 |          256
|>  >  2006-02-18 |          104
|>  >  2006-02-19 |           34
|>  >  2006-02-20 |           20
|>  >
|>  > I'm using a left join because i really need the =0 sums.
|>  > The use of substr() is due to the fact the "26-insertTime" on the
|>  > 'netopia' table has a default of 'default (now())::timestamp(2) without
|>  > time zone'. So, i can make generate_series work with the left join
|>  > using the substr. I was getting ready to optimize this query, when i
|>  > remembered i also have the need for another column, 'totalcause99',
|>  > almost the same as this query, but with 'cause01=99' as condition.
|>  >
|>  > The maximum i was able to do without syntax errors was:
|>  >
|>  > SELECT DATE_TRUNC('month', timestamp '2006-02-01' )::DATE + s.d AS
|>  > date, COUNT (o."04-sms") as totalcause98,
|>  >       COUNT (p."04-sms") as totalcause99
|>  >       FROM generate_series(11,19) AS s(d)
|>  >  LEFT JOIN netopia o ON (substr(o."26-insertTime",1,10) =
|>  > (DATE_TRUNC('month', timestamp'2006-02-01'  )::DATE + s.d) and
|>  > o.cause01=98)
|>  >  LEFT JOIN netopia p ON (substr(p."26-insertTime",1,10) =
|>  > (DATE_TRUNC('month', timestamp'2006-02-01'  )::DATE + s.d) and
|>  > p.cause01=99)
|>  >  GROUP BY s.d ORDER BY 1;
|>  >
|>  > Reading this one aloud, i feel the "logic" of what i'm trying to do,
|>  > but the values of its output are.. scary to say the least, and the sums
|>  > are exactly the same on the 2 columns, and that should never happen
|>  > with the data i have on the table.
|>  >
|>  > I'm starting to wonder if this is actually possible to be done on one
|>  > single query...
|>  > Ideas, anyone?
|>  >
|>  > Sorry for the long email.
|>  > Any and all help is deeply appreciated.
|>  >
|>  > Regards,
|>

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

   http://archives.po

Re: [SQL] ORDER BY with LTREE

2006-02-20 Thread Michael Fuhr
On Mon, Feb 20, 2006 at 11:15:43AM +0100, Axel Straschil wrote:
> I have a table with a ltree and acaption "CREATE TABLE (tree LTREE, 
> caption TEXT)", I can't store the data of caption in the ltree, becouse of 
> the limitation of the ltree labels. I use the ltree to give the captions 
> a direcory like hirachy, wenn a new caption is createt, the customer can 
> decide which is the parent caption.
> 
> My Problem now ist, that I want to show in a list-box all the captions 
> ordered by ltree, but in the same hirachy by the caption.

Maybe somebody can think of a better way, but as I mentioned in my
previous post you could create a custom operator to use in the ORDER
BY clause.  The operator's function would receive two rows: if the
rows have a common parent in the hierarchy then the function could
compare the rows' labels; otherwise it could query for other rows
and perform appropriate comparisons.  With a large table those queries
could make ordering expensive; if anybody has a better suggestion
then hopefully they'll mention it.

Below is a simple example using the data from your original message
and giving the results you requested.  It's intended to be a starting
point, not a final solution.  I have only a little experience with
ltree and with using custom operators in this manner, so corrections
and improvements are welcome.

CREATE TABLE foo (tree ltree, caption text);

INSERT INTO foo VALUES ('root.1', 'z');
INSERT INTO foo VALUES ('root.2', 'c');
INSERT INTO foo VALUES ('root.2.1', 'a');
INSERT INTO foo VALUES ('root.2.2', 'b');
INSERT INTO foo VALUES ('root.3', 'i');
INSERT INTO foo VALUES ('root.4', 'f');
INSERT INTO foo VALUES ('root.4.1', 'k');
INSERT INTO foo VALUES ('root.4.2', 'c');

CREATE FUNCTION foo_lt(foo, foo) RETURNS boolean AS $$
DECLARE
level  integer;
row1   foo%ROWTYPE;
row2   foo%ROWTYPE;
BEGIN
IF subpath($1.tree, 0, -1) = subpath($2.tree, 0, -1) THEN
RETURN $1.caption < $2.caption;
ELSIF $1.tree @> $2.tree THEN
RETURN true;
ELSE
level := nlevel(lca($1.tree, $2.tree)) + 1;
SELECT INTO row1 * FROM foo WHERE tree = subpath($1.tree, 0, level);
SELECT INTO row2 * FROM foo WHERE tree = subpath($2.tree, 0, level);
RETURN row1.caption < row2.caption;
END IF;
END;
$$ LANGUAGE plpgsql STABLE STRICT;

CREATE OPERATOR < (
PROCEDURE = foo_lt,
LEFTARG   = foo,
RIGHTARG  = foo
);

SELECT * FROM foo ORDER BY foo USING <;
   tree   | caption 
--+-
 root.2   | c
 root.2.1 | a
 root.2.2 | b
 root.4   | f
 root.4.2 | c
 root.4.1 | k
 root.3   | i
 root.1   | z
(8 rows)

-- 
Michael Fuhr

---(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