2013-02-13 117 views
7

我遇到問題。基於列名的sql更新

我有T1,T2,T_Join表。

T_Join:第一列:ID(唯一)例如:10,11,12,13。第二列:CODE,它包含的屬性等於T2的列名稱。例如:類型,來源,部分,重要性。這些由T1中的ID標識。根據這一點,屬性的ID的 '源' 是11.

ID CODE 
10 type 
11 source 
12 section 
13 importance 

在表T1,第一列是data_ID這不是唯一的:1020,1020,1020,1022,1022,1022,1023, 1023,1028,1028,1028,1035,1035等

第二列是來自T_Join的ID。在該實施例4的ID可以屬於1 data_ID,這些聲明,其中值出現在第三列(VALUE):

data_ID ID VALUE 
1020  10 1 
1020  11 123 
1020  12 9 
1020  13 4 
1022  10 2 
1022  12 15 
1023  10 2 
1023  11 108 
1023  13 2 
1028  12 20 

...

這意味着與ID 1020中的項的類型1源於No.123,是由存儲在該部分9中的該ID識別的具有第4級重要性的真實對象。

現在,我有一個表T2。第一列與T1中的data_ID相同。在這張表中這些是獨一無二的。其他欄目:(多麼令人驚訝!)類型,來源,部分,重要性。 (在現實中,不僅存在着四種屬性,但至少有五十美元!) 所以表看起來是這樣的:

data_ID type source section importance 
1020  1  123  9  2 
1022  1  95  3  5 
1023  2  108  21  4 
1028  1  147  17  5 

的T2包含新的數據。我想用這些更新T1.VALUE列。按照上面我的例子,更新後的T1應該是這樣的:

data_ID ID VALUE 
1020  10 1 
1020  11 123 
1020  12 9 
1020  13 2 
1022  10 1 
1022  12 3 
1023  10 2 
1023  11 108 
1023  13 4 
1028  12 17 
... 

所以,在data_ID 1020,其重要性是4,它原來爲2,因爲在T1的ID是13,它是指屬性「重要性'從T_Join表格等等。 我想以這種方式更新所有數據。我不是一個SQL專家,我已經成功地創建此代碼:

update T1 set VALUE = 
(select * from T2 
inner join T_Join on ID= 
(SELECT 
    c.name 
FROM 
    sys.objects o 
INNER JOIN 
    sys.columns c 
ON 
    c.object_id = o.object_id 
AND o.name = 'T2') 
where T1.data_ID = T2.data_ID and T2.ID = T_Join.ID) 

from T1 
inner join T2 on T1.data_ID = T2.data_ID 
inner join T_Join on T1.ID = T_Join.ID 

select * from T1 

,但它不工作,錯誤消息:

消息116,級別16,狀態1 ,第16行 當子查詢未與EXISTS一起引入時,只能在選擇列表中指定一個表達式。

我試圖用CURSOR語句和聲明變量(基於建議)來解決它,但它也不起作用。

請,如果有人有一個想法如何我可以解決這個問題(以最簡單的方式),答案儘可能詳細。

+0

+1你加入了很多關於你有,甚至問題的詳細信息表明你試圖解決它。這是一個很好的第一篇文章。 – Taryn 2013-02-13 15:02:38

回答

5

您目前的設計存在的問題是,您有一張表進行了規範化處理,另一個表格進行了歸一化處理,您需要執行更新。

您首先需要將T2表取消歸一化,該表將取得列並將其轉換爲行。在SQL Server 2005+中,他們介紹了將爲您執行此操作的UNPIVOT函數。

第一步是將SELECT的數據從T2T_Join轉換成行。該SELECT聲明:

select j.id, 
    j.code, 
    u.data_id, 
    u.value 
from T_Join j 
inner join 
(
    select data_id, col, value 
    from T2 
    unpivot 
    (
    value 
    for col in (type, source, section, importance) 
) unpiv 
) u 
    on j.code = u.col 

SQL Fiddle with Demo。這需要您的列數據並將其轉換爲行給出結果:

| ID |  CODE | DATA_ID | VALUE | 
------------------------------------- 
| 10 |  type | 1020 |  1 | 
| 11 |  source | 1020 | 123 | 
| 12 | section | 1020 |  9 | 
| 13 | importance | 1020 |  2 | 
| 10 |  type | 1022 |  1 | 
| 11 |  source | 1022 | 95 | 
| 12 | section | 1022 |  3 | 
| 13 | importance | 1022 |  5 | 
| 10 |  type | 1023 |  2 | 
| 11 |  source | 1023 | 108 | 
| 12 | section | 1023 | 21 | 
| 13 | importance | 1023 |  4 | 
| 10 |  type | 1028 |  1 | 
| 11 |  source | 1028 | 147 | 
| 12 | section | 1028 | 17 | 
| 13 | importance | 1028 |  5 | 

一旦數據在格式,你可以在UPDATE語句中使用它:

update t1 
set t1.value = t.value 
from t1 
inner join 
(
    select j.id, 
    j.code, 
    u.data_id, 
    u.value 
    from T_Join j 
    inner join 
    (
    select data_id, col, value 
    from T2 
    unpivot 
    (
     value 
     for col in (type, source, section, importance) 
    ) unpiv 
) u 
    on j.code = u.col 
) t 
    on t1.data_id = t.data_id 
    and t1.id = t.id; 

SQL Fiddle with Demo

您聲明的下一個問題是有大約50列需要unpivot。如果是這種情況,那麼您可以使用動態SQL來獲取列的列表以變爲行。您的動態SQL腳本將爲:

DECLARE @colsUnpivot AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @colsUnpivot = stuff((select ','+quotename(C.name) 
     from sys.columns as C 
     where C.object_id = object_id('T2') and 
       C.name not in ('data_ID') 
     for xml path('')), 1, 1, '') 

set @query 
    = 'update t1 
    set t1.value = t.value 
    from t1 
    inner join 
    (
     select j.id, 
     j.code, 
     u.data_id, 
     u.value 
     from T_Join j 
     inner join 
     (
     select data_id, col, value 
     from T2 
     unpivot 
     (
      value 
      for col in ('[email protected]+') 
     ) unpiv 
     ) u 
     on j.code = u.col 
    ) t 
     on t1.data_id = t.data_id 
     and t1.id = t.id;' 

exec(@query); 

請參閱SQL Fiddle with Demo

的代碼將更新T1結果如下:

| DATA_ID | ID | VALUE | 
------------------------ 
| 1020 | 10 |  1 | 
| 1020 | 11 | 123 | 
| 1020 | 12 |  9 | 
| 1020 | 13 |  2 | 
| 1022 | 10 |  1 | 
| 1022 | 12 |  3 | 
| 1023 | 10 |  2 | 
| 1023 | 11 | 108 | 
| 1023 | 13 |  4 | 
| 1028 | 12 | 17 | 
+0

謝謝你的回答,我會盡快檢查! – A117 2013-02-15 09:14:38