A11*_*117 7 sql t-sql sql-server unpivot
我有个问题.
我有T1
,T2
,T_Join
表.
T_Join
:第一列:( ID
唯一)例如:10,11,12,13.第二列:CODE
,它包含的属性等于列名T2
.例如:类型,来源,部分,重要性.这些是由中确定ID
的T1
.据此,属性'source'的ID是11.
ID CODE
10 type
11 source
12 section
13 importance
Run Code Online (Sandbox Code Playgroud)
在表T1
中,第一列是data_ID
这不是唯一的:1020,1020,1020,1022,1022,1022,1023,1023,1028,1028,1028,1035,1035,等
第二列是来自的ID T_Join
.在此示例中,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
Run Code Online (Sandbox Code Playgroud)
...
这意味着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
Run Code Online (Sandbox Code Playgroud)
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
...
Run Code Online (Sandbox Code Playgroud)
因此,在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
Run Code Online (Sandbox Code Playgroud)
但它不起作用,错误信息:
消息116,级别16,状态1,行16当子查询未与EXISTS一起引入时,只能在选择列表中指定一个表达式.
我尝试使用CURSOR语句和声明的变量(基于建议)解决它,但它也不起作用.
如果有人知道如何解决这个问题(以最简单的方式),请尽可能详细地回答.
您当前设计的问题是您有一个规范化的表和一个非规范化的表,您需要执行更新.
首先,您需要对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
Run Code Online (Sandbox Code Playgroud)
请参阅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 |
Run Code Online (Sandbox Code Playgroud)
一旦数据采用该格式,您就可以在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;
Run Code Online (Sandbox Code Playgroud)
您声明的下一个问题是,您需要将大约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);
Run Code Online (Sandbox Code Playgroud)
代码将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 |
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2408 次 |
最近记录: |