2013-03-25 40 views
0

我有兩個表,TblValTblAdjSQL Server通過另一個表調整列中的每個值

TblVal我有一堆,我需要根據TblAdj對於給定TblVal.PersonIDTblVal.Date調整,然後在一些ViewAdjustedValues返回的值。我必須僅應用那些TblAdj.Date >= TblVal.Date的調整。

問題是,由於所有的調整都是減法或除法,因此需要按順序進行調整。下面是表的結構:

TblValPersonID, Date, Value
TblAdjPersonID, Date, SubtractAmount, DivideAmount

我想回到ViewAdjustedValuesPersonID, Date, AdjValue

我能做到這一點,而無需使用WHILE循環和IF塊通過TblAdj迭代根據需要減去或分開?是否有一些嵌套的SELECT表魔法可以執行,速度會更快?

+0

爲什麼不將轉換爲相減?聚合起來要容易得多。 – iamsleepy 2013-03-25 23:49:17

+0

如果不知道將要應用的值,則不能將差值轉換爲差值。例如,如果除以2,則不論固定減法的數目減半,固定減法總是具有除以2的相同效果。 – 2013-03-26 00:34:56

+0

你說「因爲所有的調整要麼是**粗體** ** **粗體**減法**粗體**或者**粗體**除法」「其他」值是什麼,它是NULL嗎?他們都可以是NULL?另外,我懷疑TblAdj表的行數少於TblVal表,這是真的嗎?你也需要更新表格,或者你需要打印出結果。最後一件事,是否要在更新完成後從TblAdj中刪除元組? – Marichyasana 2013-03-27 01:28:11

回答

0

我認爲你可以做到這一點沒有環,但是否要與否是另一個問題。我認爲有效的查詢如下(SQL小提琴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; 
+0

順便說一句,我意識到你可能需要對同一個PersonID進行多次調整(即,如果PersonID不是TblVal的主鍵),所以我向最外面的GROUP BY添加了一個附加項,以便通過p.Date以及。該查詢(使用該調整)假定(TblVal.PersonID,TblVal.Date,TblVal.Value)是唯一的。 – 2013-03-26 00:45:12

+0

嘿,這很好,非常感謝!另外,您的整個行都代表「TblVal」的唯一條目,而不僅僅是「PersonID」。 不幸的是,我們仍在運行SQL Server 2005.在與同事重新分析問題之後,我們正在考慮計算數據庫之外的調整值,然後將它們存儲在額外的'AdjustedValue'列中,並且有另一個表中存儲'PersonID'和'AdjustedDate'列,我們可以在'AdjTable'中檢查該PersonID的最近日期,看看我們是否需要重新計算AdjustedValue。 – paulthegreat 2013-03-26 20:04:48

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 
相關問題