我有一个问题。
我有T1
,T2
,T_Join
个表。
T_Join
:第一栏:ID
(唯一)例如:10,11,12,13。第二列:CODE
,它包含的属性等于T2
的列名。例如:类型,来源,部分,重要性。这些内容由ID
中的T1
标识。据此,属性的来源'来源'是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,它指的是属性' important'来自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
但它不起作用,错误信息:
Msg 116,Level 16,State 1,Line 16 当未使用EXISTS引入子查询时,只能在选择列表中指定一个表达式。
我尝试使用CURSOR语句和声明的变量(基于建议)来解决它,但它也不起作用。
如果有人知道如何解决这个问题(以最简单的方式),请尽可能详细地回答。
答案 0 :(得分:5)
您当前设计的问题是您有一个规范化的表和一个非规范化的表,您需要执行更新。
首先,您需要对T2
表进行反规范化,该表将获取列并将其转换为行。在SQL Server 2005+中,他们引入了UNPIVOT
函数,它将为您执行此操作。
第一步是将SELECT
和T2
中的数据T_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;
您声明的下一个问题是, unpivot 需要大约50列。如果是这种情况,那么您可以使用动态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 ('+@colsUnpivot+')
) unpiv
) u
on j.code = u.col
) t
on t1.data_id = t.data_id
and t1.id = t.id;'
exec(@query);
代码将使用以下结果更新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 |