Select x times for each row without union
Is it possible to write union select queries like the following more succintly?
select
id,
1,
(1 + @defCapUp) * (p.Value + p.Premium),
getdate()
from Products p
union
select
id,
1,
(1 - @defCapDown) * (p.Value - p.Premium),
getdate()
from Products p
union
select
id,
case when p.Paydate > getdate() then 1 else 0 end,
(1 - @defCapUp) * (p.Value - p.Premium),
@nextYear
from Products p
union
select
id,
case when p.Paydate > getdate() then 1 else 0 end,
(1 + @defCapDown) * (p.Value + p.Premium),
@nextYear
from Products p
The statement selects four rows for each row in the Products table. The only thing varying is the formula used to calculate the values for column two and tree. I think there should be a way in sql to write the above without so much ugly code duplication. If only functions were first class objects and sql allowed lambda expressions...
Richard's solution down below is perfect, works very well for the example provided. But I had two typos in the orignal example which makes the problem somewhat tougher:
select
id,
1,
(1 + @defCapUp) * (p.Value + p.Premium),
getdate()
from Products p
union
select
id,
1,
(1 - @defCapDown) * (p.Value - p.Payout),
getdate()
from Products p
union
select
id,
case when p.Paydate > getdate() then 1 else 0 end,
(1 - @defCapUp) * (p.Value - p.Premium),
@nextYear
from Products p
union
select开发者_如何学运维
id,
case when p.Paydate <= getdate() then 1 else 0 end,
(1 + @defCapDown) * (p.Value + p.Payout),
@nextYear
from Products p
The big problem is the case expression in which the comparison operator differs. My problem is that it is very hard to "neatly" handle those cases. What if there were a third case where the comparison was p.Paydate = getdate() for example?
(Not sure how lambda expressions would have helped you)
select
id,
case when p.Paydate > X.CompareDate then 1 else 0 end,
(1 + Cap) * (p.Value + ModF * p.Premium),
@nextYear
from Products p
cross join (
select @defCapUp Cap, Cast(0 as datetime) CompareDate, 1 Modf union all
select -@defCapDown, 0, -1 union all
select -@defCapUp, GETDATE(), -1 union all
select @defCapDown, GETDATE(), 1
) X
BTW, you should have been using UNION ALL, not UNION.
If the order doesn't matter, you could use WHERE
.
SELECT id, field2, field3, field4
FROM Products p
WHERE (
field4 = getdate() AND field2=1 AND
(
field3=(1 + @defCapUp) * (p.Value + p.Premium) OR
field3=(1 - @defCapDown) * (p.Value - p.Premium)
)
)
OR
(
field4=@nextYear AND field2=(case when p.Paydate > getdate() then 1 else 0 end) AND
(
field3=(1 - @defCapUp) * (p.Value - p.Premium) OR
field3=(1 + @defCapDown) * (p.Value + p.Premium)
)
)
精彩评论