基于列名的sql更新

Posted

技术标签:

【中文标题】基于列名的sql更新【英文标题】:sql update based on column names 【发布时间】:2013-02-13 11:01:10 【问题描述】:

我有问题。

我有T1T2T_Join 表。

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

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

消息 116,第 16 级,状态 1,第 16 行 当子查询不使用 EXISTS 引入时,选择列表中只能指定一个表达式。

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

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

【问题讨论】:

+1 您提供了很多有关您遇到的问题的详细信息,甚至还展示了您尝试解决的问题。这是一篇很好的第一篇文章。 【参考方案1】:

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

首先,您需要对 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。

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

【讨论】:

感谢您的回答,我会尽快查看!

以上是关于基于列名的sql更新的主要内容,如果未能解决你的问题,请参考以下文章

SQL篇章SQL语句梳理 :--基于MySQL5.6已梳理:ALTER TABLE解析

查询中的 SQL 无效列名检测

关于数据库更新/插入速率限制的一些查询(基于 SQL 或基于 NoSQL)

基于 SQL 中的行 ID 合并列的问题

在 sql server 中使用查询输出作为列名

基于PySpark的航天日志分析(SQL分析)