2012-07-20 62 views
1

我在這裏需要更新一些記錄表結構T-SQL更新數據查詢

表A是我們需要更新一些記錄 A(身份證,DataYear0,DataYear1,DataYear3)

主要原因之一

表B具有比我們需要 B(標識,年份,DataYear)

實施例的數據表B數據的某些其它: B(ABC,1950,1.25) B(ABC,1951,1.29) 。 。 .. B(abc, 2008,1.67) B(ABC,2009,1.23) B(ABC,2010,1.52) B(ABC,2011,1.78) B(ABC,2012,NULL)

隨着2012作爲當前年份,我需要更新表A中前三年(即2011,2010,2009)的數據值。表A

因此,表A需要更新爲A(abc,1.78,1.52,1.23)上面的例子。同樣的其他記錄需要更新。

Id是兩個表上的主鍵。

查詢我至今是

UPDATE A SET 
    DataYear0 = CASE WHEN Year+1 = YEAR(GETDATE()) THEN DataYear END, 
    DataYear1 = CASE WHEN Year+2 = YEAR(GETDATE()) THEN DataYear END, 
    DataYear2 = CASE WHEN Year+3 = YEAR(GETDATE()) THEN DataYear END 
FROM A 
LEFT JOIN B 
    ON A.Id=B.Id 

這沒有工作,因爲我覺得這是從我們即要在年內開退回多餘年的記錄,只是在過去三年

UPDATE A SET 
    DataYear0 = CASE WHEN Year+1 = YEAR(GETDATE()) THEN DataYear END, 
    DataYear1 = CASE WHEN Year+2 = YEAR(GETDATE()) THEN DataYear END, 
DataYear2 = CASE WHEN Year+3 = YEAR(GETDATE()) THEN DataYear END 
FROM A 
LEFT JOIN B 
    ON A.Id=B.Id 
GROUP BY Id,Year,DataYear 
HAVING ((YEAR(GETDATE())-3) <= Year) AND (Year <> YEAR(GETDATE())) 

但仍然沒有更新數據。

使用CTE

;WITH cte AS 
(
SELECT 
    A.Id 
    ,B.Year 
    ,B.DataYear 
    ,ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Year DESC) as row 
FROM A 
LEFT JOIN B 
    ON A.Id=B.Id 
GROUP BY Id,Year,DataYear 
HAVING ((YEAR(GETDATE())-3) <= Year) AND (Year <> YEAR(GETDATE())) 
) 


UPDATE 
    A.DataYear0 = CASE WHEN row=1 THEN DataYear END 
    ,A.DataYear1 = CASE WHEN row=2 THEN DataYear END 
    ,A.DataYear2 = CASE WHEN row=3 THEN DataYear END 
FROM A 
LEFT JOIN cte 
    ON A.Id = cte.Id 

的數據仍然沒有更新嘗試。我將不勝感激任何人的建議。提前謝謝了。

+1

ID沒有在表B中的主鍵(這不是唯一的)。 – GilM 2012-07-20 22:54:44

+0

是的,你是對的。對不起,我應該澄清一點。 – JustCurious 2012-07-21 06:48:11

回答

2

你可以做這樣的事情:

UPDATE a 
    SET DataYear0 = COALESCE(d0.DataYear,DataYear0), 
     DataYear1 = COALESCE(d1.DataYear,DataYear1), 
     DataYear2 = COALESCE(d2.DataYear,DataYear2) 
FROM A a 
LEFT JOIN B d0 ON d0.Id = a.Id and d0.[Year] = YEAR(GETDATE())-1 
LEFT JOIN B d1 ON d1.Id = a.Id and d1.[Year] = YEAR(GETDATE())-2 
LEFT JOIN B d2 ON d2.Id = a.Id and d2.[Year] = YEAR(GETDATE())-3 
+0

+1,非常好。 – 2012-07-20 22:51:42

+0

'COALESCE()'與原始值可能不是錯過年份的正確值。當然,我們有限的信息有點難以推測。確切地說,是 – shawnt00 2012-07-20 22:57:06

+0

。我猜測,如果沒有行,我們不想將其更改爲NULL,但如果不是這種情況,只需將它們替換爲d0.DataYear,d1.DataYear,d2.DataYear就很容易。 – GilM 2012-07-20 23:03:41

0
UPDATE A 
SET 
    DataYear0 = (SELECT DataYear FROM B WHERE A.id = B.id AND Year = YEAR(GETDATE()) - 1), 
    DataYear1 = (SELECT DataYear FROM B WHERE A.id = B.id AND Year = YEAR(GETDATE()) - 2), 
    DataYear2 = (SELECT DataYear FROM B WHERE A.id = B.id AND Year = YEAR(GETDATE()) - 3) 

UPDATEFROM子句不是標準的SQL。這種方法看起來有點冗長,但它是正確的方式,優化器仍然可以有效地處理它。

如果任何子查詢不是標量結果,這也會導致錯誤,這是一件好事。其他人的回答將允許這樣做。

+0

非常感謝您的代碼和解釋。有用!非常感謝,再次。 – JustCurious 2012-07-21 06:56:43

2

此問題源於嘗試從多行更新單行。要查看它,請將您的更新轉換爲選擇。在這種情況下,最後更新者獲勝,將其他兩列作爲空值。要解決這個問題,可以使用子查詢或某種方式將行轉換爲列,如pivot。現在

,過度設計的樂趣:

update A 
set DataYear0 = pvt.[0], 
    DataYear1 = pvt.[1], 
    DataYear2 = pvt.[2] 
from A 
inner join 
(
    select u.ID, u.[0], u.[1], u.[2] 
    from 
    (
    select b.id, 
      3 - (year(getdate()) - b.Year) YearOffset, 
      b.DataYear 
     from B 
    where b.Year >= year(getdate()) - 3 
     and b.Year < year(getdate()) 
) p 
    pivot (min(DataYear) 
     for YearOffset in ([0], [1], [2]) 
) u 
) pvt 
on A.id = pvt.id; 

You may see this query in action @ Sql Fiddle

+0

感謝您的解釋。有用!真是輝煌!再次感謝!! – JustCurious 2012-07-21 06:52:47