开发者

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)
  )
)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜