0

我有两张桌子,TblValTblAdj

TblVal我有一堆值,我需要根据给TblAdj定的值进行调整TblVal.PersonIDTblVal.Date然后返回一些ViewAdjustedValues. 我必须只应用那些调整TblAdj.Date >= TblVal.Date

麻烦的是,由于所有的调整要么是减法,要么是除法,所以需要按顺序进行。这是表结构:

TblVal: PersonID, Date, Value
TblAdj:PersonID, Date, SubtractAmount, DivideAmount

我想返回ViewAdjustedValuesPersonID, Date, AdjValue

我可以在不TblAdj使用WHILE循环和IF块进行迭代的情况下根据需要进行减法或除法吗?是否有一些我可以执行的嵌套 SELECT 表魔术会更快?

4

2 回答 2

0

尝试以下操作:


with CTE_TblVal (PersonID,Date,Value)
as 
(
   select A.PersonID, A.Date, A.Value 
   from TblVal A
   inner join TblAdj B
   on A.PersonID = B.PersonID
   where B.Date >= A.Date
)
update CTE_TblVal
set Date = TblAdj.Date,
    Value = TblAdj.Value
from CTE_TblVal
   inner join TblAdj 
   on CTE_Tblval.PersonID = TblAdj.PersonID
output inserted.* into ViewAdjustedValues
select * from ViewAdjustedValues 
于 2013-03-25T23:42:07.767 回答
0

我认为你可以在没有循环的情况下做到这一点,但你是否愿意是另一个问题。我认为有效的查询如下(SQL Fiddle here)。关键思想如下:

每个 SubtractAmount 的最终效果是减去 SubtractAmount 除以同一 PersonID 的所有后续 DivideAmount 的乘积。与 PersonID 关联的日期与此调整无关(幸运的是)。CTE AdjustedAdjustments 包含这些调整后的 SubtractAmount 值。

PersonID 的初始值除以该人员日期当天或之后的所有 DivideAmount 值的乘积。

如果 x 的所有值都是正数,则 EXP(SUM(LOG(x))) 用作聚合产品。您应该限制 DivideAmount 值以确保这一点,或相应地调整代码。

如果没有 DivideAmounts,则关联产品为 NULL 并更改为 1。类似地,调整后的 SubtractAmount 值的 NULL 总和更改为零。左连接用于保留不受任何调整的值。

SQL Server 2012 支持聚合的 OVER 子句,这有助于聚合“所有以后的 DivideAmounts”。

WITH AdjustedAdjustments AS (

select
  PersonID,
  Date,
  SubtractAmount/
  EXP(
    SUM(LOG(COALESCE(DivideAmount,1)))
      OVER (
        PARTITION BY PersonID
        ORDER BY Date
        ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
      )
  ) AS AdjustedSubtract,
  DivideAmount
  FROM TblAdj
)

  SELECT
    p.PersonID,
    p.Value/COALESCE(EXP(SUM(LOG(COALESCE(DivideAmount,1)))),1)
      -COALESCE(SUM(a.AdjustedSubtract),0) AS AmountAdjusted
  FROM TblVal AS p
  LEFT OUTER JOIN AdjustedAdjustments AS a
  ON a.PersonID = p.PersonID
  AND a.Date >= p.Date
  GROUP BY p.PersonID, p.Value, p.Date;
于 2013-03-26T00:31:18.970 回答