Вопрос

I need help with a problem I've been scratching my head and so far I couldn't solve. This is not a specific question about jOOQ, but I refer it to explain why I have to use joins instead of the ingres specific syntax. That said:

Imagine the following table and values:

create table  orderline
 (orderno integer,
 lineno integer,
 linetime timestamp,
 article varchar(30)
 );
insert into orderline values (1,1,timestamp '2013-10-23 00:05:08.0', 'SMURFS');
insert into orderline values (1,2,timestamp '2013-10-23 00:05:08.0', 'PINKMAN');
insert into orderline values (1,3,timestamp '2013-10-23 00:05:10.0', 'METH FAIRY');
insert into orderline values (1,4,timestamp '2013-10-23 00:05:12.0', 'HEISENBERG');
insert into orderline values (2,1,timestamp '2013-10-23 00:08:13.0', 'HEAR ME ROAR');
insert into orderline values (2,2,timestamp '2013-10-23 00:08:15.0', 'KHAALESI');
insert into orderline values (2,3,timestamp '2013-10-23 00:09:01.0', 'UNSULLIED');
insert into orderline values (2,4,timestamp '2013-10-23 00:09:03.0', 'WHITE WALKERS');
insert into orderline values (2,5,timestamp '2013-10-23 00:09:03.0', 'WILDLING');

Now what I am given is only the an interval to search on this table. The result that I have to give is all order lines from an specific order, where one line at least matches the time interval.

For example, the interval between 2013-10-23 00:05:08.0 and 2013-10-23 00:05:09.0, inclusive,should give as a result on my query the 4 lines with orderno=1, but only 2 lines match the interval: the line with orderno =1, lineno = 1 and the line with orderno=1, lineno=2. A simple query using the interval with only return those 2 lines.

On old ingres times, I would search like this:

select * from orderline
where orderno in (
select orderno from orderline
  where linetime >= timestamp '2013-10-23 00:05:08.0'
  and linetime <= timestamp '2013-10-23 00:05:09.0'
)
order by orderno, lineno

this gives exactly the 4 lines I need. But I can't use this syntax because I have to use jOOQ and this syntax doesn't exist there (have to use joins). I can't make it work with joins though.

The following query:

select * from orderline a
join orderline b
on a.orderno = b.orderno 
where b.linetime >= timestamp '2013-10-23 00:05:08.0'
and b.linetime <= '2013-10-23 00:05:09.0'

produces 8 lines, i.e each line comes duplicated.

If I use the 2 conditions (orderno and lineno) as join conditions, i.e

select * from orderline a
join orderline b
on a.orderno = b.orderno and a.lineno = b.lineno
where b.linetime >= timestamp '2013-10-23 00:05:08.0'
and b.linetime <= '2013-10-23 00:05:09.0'

I get only 2 lines, exactly as if I had made a direct simple query on the interval. Experiments with right, left, inner, etc joins didn't yield any result so far so I'm clueless as to how to do it (and therefore be able to write it on jOOQ).

Anyone knows how should I make this query on SQL92 (i.e. join) syntax?

Это было полезно?

Решение

All standard SQL statements and clauses are supported in jOOQ. E.g. your statement:

select * from orderline
where orderno in (
select orderno from orderline
  where linetime >= timestamp '2013-10-23 00:05:08.0'
  and linetime <= timestamp '2013-10-23 00:05:09.0'
)
order by orderno, lineno

Corresponds to this in jOOQ (3.2 syntax):

// Assuming this static import:
import static org.jooq.impl.DSL.*;

using(configuration)
.select().from(ORDERLINE)
.where(ORDERLINE.ORDERNO.in(
    select(ORDERLINE.ORDERNO)
    .from(ORDERLINE)
    .where(ORDERLINE.LINETIME.ge(Timestamp.valueOf("2013-10-23 00:05:08.0")))
    .and(ORDERLINE.LINETIME.le(Timestamp.valueOf("2013-10-23 00:05:09.0")))
))
.orderBy(ORDERLINE.ORDERNO, ORDERLINE.LINENO)
.fetch();

About your JOIN alternatives:

The best way to solve this is using a semi-join the way you did, using an IN or EXISTS predicate. You could use a regular equi-join on orderno, but you'd have to join a derived table where you get only distinct orderno values:

select * 
from orderline a
join (
    select distinct orderno
    from orderline
    where linetime >= timestamp '2013-10-23 00:05:08.0'
    and linetime <= timestamp '2013-10-23 00:05:09.0'
) b
on a.orderno = b.orderno
order by orderno, lineno

I doubt that this variant is faster or easier to maintain

Другие советы

You wrote:

I get only 2 lines, exactly as if I had made a direct simple query on the interval.

But there is only one time matching the interval.

I think there is a typo, difference. And probably this second line causes the issue.

Anyway you can easily remove duplications if you change the first select to select distinct.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top