Hello,

I'm rusty with SQL and I've started to practice it again but I'm falling on this issue.

The problem:

Extracting rows from 'b' table trapping min() of a calculated value "days" on 'a' table and a parameter.

SELECT b.*,
       $1::date-a.sincedate AS "days"
  FROM b, a
 WHERE pintime BETWEEN $2 AND $2::interval+'00:01:00'::interval
       AND b.a_id=a.id AND a.genre='F' AND description ~*'35$'
ORDER BY $1::date-a.sincedate ASC;

attached there is the full example, data, creates and inserts for it.

$1 can by any date (now() for example is good enough)
$2 is a time interval (10:00 in the example).

I thank you in advance for any answer.


Bye,             \ferz
The problem:

SELECT pintime,a_id,c_id,value,id,sincedate,todate,description, genre, 
now()::date-a.sincedate AS "days" 
  FROM b, a 
 WHERE pintime BETWEEN '10:00:00' AND '10:00:00'::interval+'00:01:00'::interval 
       AND b.a_id=a.id AND a.genre='F' AND description ~*'35$' 
ORDER BY now()::date-a.sincedate ASC;
 pintime  | a_id | c_id | value | id | sincedate  |   todate   | description | 
genre | days 
----------+------+------+-------+----+------------+------------+-------------+-------+------
 10:00:00 |    2 |    1 |  1100 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    2 |  1200 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    3 |  1300 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    4 |  1400 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    5 |  1500 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    4 |    1 |  4100 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
 10:00:00 |    4 |    2 |  4200 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
 10:00:00 |    4 |    3 |  4300 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
 10:00:00 |    4 |    4 |  4400 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
 10:00:00 |    4 |    5 |  4500 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
 10:00:00 |    5 |    1 |  5100 |  5 | 2010-09-02 | 2010-10-10 | a 35        | 
F     |  416
 10:00:00 |    5 |    4 |  5400 |  5 | 2010-09-02 | 2010-10-10 | a 35        | 
F     |  416
 10:00:00 |    5 |    6 | 10600 |  5 | 2010-09-02 | 2010-10-10 | a 35        | 
F     |  416
(13 rows)

I need to extract rows having the lower number of days for each a_id,c_id pair. 
The wanted result of the new query has to be: 

 pintime  | a_id | c_id | value | id | sincedate  |   todate   | description | 
genre | days 
----------+------+------+-------+----+------------+------------+-------------+-------+------
 10:00:00 |    2 |    1 |  1100 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    2 |  1200 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    3 |  1300 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    4 |  1400 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    5 |  1500 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    6 |    6 | 10600 |  6 | 2010-09-02 | 2010-10-10 | a 35        | 
F     |  416
(13 rows)

Since c_id=6 has not any result for days<416;
So which are ways to write such SQL query?


Data:

create table a (id integer primary key, sincedate date not null, todate date 
not null, description text, genre char(1) default 'M');
create table c (id integer primary key, name text not null, someotherdata  
text);
create table b (pintime interval not null, a_id integer not null references a, 
c_id integer not null references c, value integer, primary key(a_id,c_id));

insert into a (id,sincedate, todate, description, genre)
       values (1,'20110502','20110527','a 15','F'),
              (2,'20110502','20110527','a 35','F'),
              (3,'20110502','20110527','b 35','M'),
              (4,'20110311','20110323','a 35','F'),
              (5,'20100902','20101010','a 35','F');
insert into c (id,name) values 
(1,'c1'),(2,'c2'),(3,'c3'),(4,'c4'),(5,'c5'),(6,'c6');
insert into b (pintime,a_id,c_id,value) values 
('10:00',1,1,100),('10:00',1,2,200),('10:00',1,3,300),('10:00',1,4,400),('10:00',1,5,500);
insert into b (pintime,a_id,c_id,value) values 
('10:00',2,1,1100),('10:00',2,2,1200),('10:00',2,3,1300),('10:00',2,4,1400),('10:00',2,5,1500);
insert into b (pintime,a_id,c_id,value) values 
('10:00',3,1,3100),('10:00',3,2,3200),('10:00',3,3,3300),('10:00',3,4,3400),('10:00',3,5,3500);
insert into b (pintime,a_id,c_id,value) values 
('10:00',4,1,4100),('10:00',4,2,4200),('10:00',4,3,4300),('10:00',4,4,4400),('10:00',4,5,4500);
insert into b (pintime,a_id,c_id,value) values 
('10:00',5,1,5100),('10:00',5,4,5400),('10:00',5,6,10600);

select * from a;
 id | sincedate  |   todate   | description | genre 
----+------------+------------+-------------+-------
  1 | 2011-05-02 | 2011-05-27 | a 15        | F
  2 | 2011-05-02 | 2011-05-27 | a 35        | F
  3 | 2011-05-02 | 2011-05-27 | b 35        | M
  4 | 2011-03-11 | 2011-03-23 | a 35        | F
  5 | 2010-09-02 | 2010-10-10 | a 35        | F
(6 rows)

select * from b;

 pintime  | a_id | c_id | value 
----------+------+------+-------
 10:00:00 |    1 |    1 |   100
 10:00:00 |    1 |    2 |   200
 10:00:00 |    1 |    3 |   300
 10:00:00 |    1 |    4 |   400
 10:00:00 |    1 |    5 |   500
 10:00:00 |    2 |    1 |  1100
 10:00:00 |    2 |    2 |  1200
 10:00:00 |    2 |    3 |  1300
 10:00:00 |    2 |    4 |  1400
 10:00:00 |    2 |    5 |  1500
 10:00:00 |    3 |    1 |  3100
 10:00:00 |    3 |    2 |  3200
 10:00:00 |    3 |    3 |  3300
 10:00:00 |    3 |    4 |  3400
 10:00:00 |    3 |    5 |  3500
 10:00:00 |    4 |    1 |  4100
 10:00:00 |    4 |    2 |  4200
 10:00:00 |    4 |    3 |  4300
 10:00:00 |    4 |    4 |  4400
 10:00:00 |    4 |    5 |  4500
 10:00:00 |    5 |    1 |  5100
 10:00:00 |    5 |    4 |  5400
 10:00:00 |    5 |    6 | 10600
(23 rows)

select * from c;

 id | name | someotherdata 
----+------+---------------
  1 | c1   | 
  2 | c2   | 
  3 | c3   | 
  4 | c4   | 
  5 | c5   | 
  6 | c6   | 
(6 rows)

SELECT *, now()::date-a.sincedate AS "days" 
  FROM b, a 
 WHERE pintime BETWEEN '10:00:00' AND '10:00:00'::interval+'00:01:00'::interval 
       AND c_id=5 AND b.a_id=a.id AND a.genre='F' AND description ~*'35$';

 pintime  | a_id | c_id | value | id | sincedate  |   todate   | description | 
genre | days 
----------+------+------+-------+----+------------+------------+-------------+-------+------
 10:00:00 |    2 |    5 |  1500 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    4 |    5 |  4000 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
(2 rows)


How to write a query to choose the result a.id with with less days?

 pintime  | a_id | c_id | value | id | sincedate  |   todate   | description | 
genre | days 
----------+------+------+-------+----+------------+------------+-------------+-------+------
 10:00:00 |    2 |    5 |  1500 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174


This is the wrong way:
SELECT pintime,a_id,c_id,value,id,sincedate,todate,description, genre, 
now()::date-a.sincedate AS "days" 
  FROM b, a 
 WHERE pintime BETWEEN '10:00:00' AND '10:00:00'::interval+'00:01:00'::interval 
       AND c_id=5 AND b.a_id=a.id AND a.genre='F' AND description ~*'35$' 
GROUP BY pintime,a_id,c_id,value,id,sincedate,todate,description, genre 
HAVING now()::date-a.sincedate=min(now()::date-a.sincedate);
 pintime  | a_id | c_id | value | id | sincedate  |   todate   | description | 
genre | days 
----------+------+------+-------+----+------------+------------+-------------+-------+------
 10:00:00 |    4 |    5 |  4000 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
 10:00:00 |    2 |    5 |  1500 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
(2 rows)


This gives the right result:

SELECT pintime,a_id,c_id,value,id,sincedate,todate,description, genre, 
now()::date-a.sincedate AS "days" 
  FROM b, a 
 WHERE pintime BETWEEN '10:00:00' AND '10:00:00'::interval+'00:01:00'::interval 
       AND c_id=5 AND b.a_id=a.id AND a.genre='F' AND description ~*'35$' 
ORDER BY now()::date-a.sincedate ASC LIMIT 1;

but what if I use this without the c_id=5 condition?


Then the problem (again):

SELECT pintime,a_id,c_id,value,id,sincedate,todate,description, genre, 
now()::date-a.sincedate AS "days" 
  FROM b, a 
 WHERE pintime BETWEEN '10:00:00' AND '10:00:00'::interval+'00:01:00'::interval 
       AND b.a_id=a.id AND a.genre='F' AND description ~*'35$' 
ORDER BY now()::date-a.sincedate ASC;
 pintime  | a_id | c_id | value | id | sincedate  |   todate   | description | 
genre | days 
----------+------+------+-------+----+------------+------------+-------------+-------+------
 10:00:00 |    2 |    1 |  1100 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    2 |  1200 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    3 |  1300 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    4 |  1400 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    5 |  1500 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    4 |    1 |  4100 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
 10:00:00 |    4 |    2 |  4200 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
 10:00:00 |    4 |    3 |  4300 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
 10:00:00 |    4 |    4 |  4400 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
 10:00:00 |    4 |    5 |  4500 |  4 | 2011-03-11 | 2011-03-23 | a 35        | 
F     |  226
 10:00:00 |    5 |    1 |  5100 |  5 | 2010-09-02 | 2010-10-10 | a 35        | 
F     |  416
 10:00:00 |    5 |    4 |  5400 |  5 | 2010-09-02 | 2010-10-10 | a 35        | 
F     |  416
 10:00:00 |    5 |    6 | 10600 |  5 | 2010-09-02 | 2010-10-10 | a 35        | 
F     |  416
(13 rows)

I need to extract rows having the lower number of days for each a_id,c_id pair. 
The wanted result of the new query has to be: 

 pintime  | a_id | c_id | value | id | sincedate  |   todate   | description | 
genre | days 
----------+------+------+-------+----+------------+------------+-------------+-------+------
 10:00:00 |    2 |    1 |  1100 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    2 |  1200 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    3 |  1300 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    4 |  1400 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    2 |    5 |  1500 |  2 | 2011-05-02 | 2011-05-27 | a 35        | 
F     |  174
 10:00:00 |    6 |    6 | 10600 |  6 | 2010-09-02 | 2010-10-10 | a 35        | 
F     |  416
(13 rows)

Since c_id=6 has not any result for days<416;
So which are ways to write such SQL query?
-- 
Sent via pgsql-sql mailing list (pgsql-sql@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-sql

Reply via email to