March 10, 2005 at 7:54 am
Dear all,
I have 3 tables C, K and CtoK. C and K have a primary key (id). CtoK associates id from C with 8 possible id from K. CtoK = (idc int ,idw int, index int) where index >= 0 and index < 8. c has also a datetime column 'creationdate'.
I want to retrieve every records from C within a particular date range. This is easy. But with each returned record I also want every corresponding id from K.
I have a solution with a temporary table. It works, but it's slow. c is huge.
I thought about this :
select C.id, k0.id, k1.id
from c
left outer join ( select idk, idc from CtoK where index = 0 ) k0 on k0.idc = c.id )
...
left outer join ( select idk, idc from CtoK where index = 7 ) k7 on k7.idc = c.id )
where c.creationdate <= @begin_date and c.creationdate < @end_date
This works but I wonder if it is a good way to do that ?
If the maximum value for index is changed, the code has to be rewritten. Is there a way to avoid that ? I thought about concataning the kx.id into a string but could not achieve that...
Thank you for your help.
This is maybe a common problem, so I apologize if it has already been posted several to this forum.
Patrick
Patrick Duflot
March 10, 2005 at 8:25 am
Since the join is expensive, I'd do it once in a derived table, then pivot the results to translate each index row into a column:
Select dt.ID,
Max( (Case Index When 0 Then 1 Else 0 End) * IdK ) As id_k0,
Max( (Case Index When 1 Then 1 Else 0 End) * IdK ) As id_k1,
Max( (Case Index When 2 Then 1 Else 0 End) * IdK ) As id_k2,
<fill in the rest>
Max( (Case Index When 7 Then 1 Else 0 End) * IdK ) As id_k7
From
(
Select C.Id, CtoK.IdK, Index
From C
Inner Join CtoK
On (C.Id = CtoK.IdC)
Where c.creationdate <= @begin_date and c.creationdate < @end_date
) dt
Group By dt.Id
March 11, 2005 at 2:11 am
Thank you very much for your reply, it really speeds up the query
Another question comes to my mind. If I need to return more fields from c or from other joined tables, should I add them to the group by clause or use another derived table ?
In extenso :
Select dt.ID,
Max( (Case Index When 0 Then 1 Else 0 End) * IdK ) As id_k0,
Max( (Case Index When 1 Then 1 Else 0 End) * IdK ) As id_k1,
Max( (Case Index When 2 Then 1 Else 0 End) * IdK ) As id_k2,
<fill in the rest>
Max( (Case Index When 7 Then 1 Else 0 End) * IdK ) As id_k7
<other fields>
From
(
Select C.Id, CtoK.IdK, Index, <other fields>
From C
left outer Join CtoK
On (C.Id = CtoK.IdC)
inner join <other source tables>
Where c.creationdate <= @begin_date and c.creationdate < @end_date
) dt
Group By dt.Id, <other fields>
or
Select dt2.ID, dt2.id_k0,... id_k7, <other fields>
from (
Select dt.ID,
Max( (Case Index When 0 Then 1 Else 0 End) * IdK ) As id_k0,
Max( (Case Index When 1 Then 1 Else 0 End) * IdK ) As id_k1,
Max( (Case Index When 2 Then 1 Else 0 End) * IdK ) As id_k2,
<fill in the rest>
Max( (Case Index When 7 Then 1 Else 0 End) * IdK ) As id_k7
From
(
Select C.Id, CtoK.IdK, Index
From C
Inner Join CtoK
On (C.Id = CtoK.IdC)
Where c.creationdate <= @begin_date and c.creationdate < @end_date
) dt
Group By dt.Id
) dt2
inner join <other source tables>
I don't see a great difference on my test system, but i am afraid that on production system, solution 1 would be too memory consuming, because of the 8 duplication of every aggregated fields in the dt table. Am I right ?
Once again your help is really appreciated
Patrick Duflot
Viewing 3 posts - 1 through 2 (of 2 total)
You must be logged in to reply to this topic. Login to reply