7

我有个问题。

我有T1, T2,T_Join表。

T_Join:第一列:(ID唯一)例如:10,11,12,13。第二列:CODE,它包含与 的列名相同的属性T2。例如:类型、来源、部分、重要性。这些由ID中的标识T1。据此,属性“源”的 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 等。

第二列是来自 的 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

...

表示 ID 为 1020 的项目是第 1 类,来自第 123 号源,此 ID 标识的真实对象存储在第 9 节中,具有第 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

但它不起作用,错误消息:

Msg 116, Level 16, State 1, Line 16 当子查询没有用 EXISTS 引入时,只能在选择列表中指定一个表达式。

我试图用 CURSOR 语句和声明的变量(基于建议)来解决它,但它也不起作用。

请,如果有人知道我该如何解决这个问题(以最简单的方式),请尽可能详细地回答。

4

1 回答 1

5

您当前设计的问题是您有一个规范化的表和一个非规范化的表,您需要执行更新。

首先,您需要对表格进行反规范化,该T2表格将获取列并将其转换为行。在 SQL Server 2005+ 中,他们介绍了UNPIVOT将为您执行此操作的功能。

第一步是SELECT从行到行的T2数据T_JoinSELECT声明是:

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

您说的下一个问题是您需要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);

请参阅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 |
于 2013-02-13T11:21:30.460 回答