2011-05-18 67 views
1

由于有2个表:我可以使用1个SQL语句更新多个记录,其中更新值取决于正在更新的记录吗?

  1. 州(持有可用状态的列表) - 键字段= STATE_ID。另一个关键是DOMAIN_ID,STATE_NAME。因此,存在具有相同STATE_NAME但具有不同DOMAIN_ID的记录。
  2. OBJECTS(包含所有对象的列表,每个对象都有自己的状态) - 键字段= OBJECT_ID。还包含一个字段STATE_ID。

假设我有一个约1000个对象的列表,它们需要在各自的域中更新为状态“CLOSED”。

对于一个单独的对象(说OBJECT_ID 12345),我可以使用SQL语句:

update OBJECTS 
set STATE_ID = 
(
    select STATE_ID from STATES 
    where STATE_NAME= 'CLOSED' 
    and DOMAIN_ID = 
    (
    select DOMAIN_ID from STATES a, OBJECTS b 
    where a.STATE_ID = b.STATE_ID and b.OBJECT_ID = 12345) 
) 
) where OBJECT_ID = 12345 

是否可以使用一个语句来更新不止一个对象吗?问题的症结似乎是我无法在SQL语句中的两个地方定义OBJECT_ID。

出于显而易见的原因,下面的语句是行不通的:

update OBJECTS 
set STATE_ID = 
(
    select STATE_ID from STATES 
    where STATE_NAME= 'CLOSED' 
    and DOMAIN_ID = 
    (
    select DOMAIN_ID from STATES a, OBJECTS b 
    where a.STATE_ID = b.STATE_ID and b.OBJECT_ID in 
    (
     select distinct OBJECT_ID from OBJECTS_TO_UPDATE 
    ) 
) 
) where OBJECT_ID in (select distinct OBJECT_ID from OBJECTS_TO_UPDATE) 

任何人可以给我什么我可以做这一轮工作的提示?

谢谢。

+0

由于一些RDBMS允许某些其他人不知道的语法,你在使用什么? (甲骨文,MySQL等?) – MatBailie 2011-05-18 13:45:32

回答

0

您可以使用表名OBJECTS,因为它在范围内,例如

UPDATE OBJECTS 
    SET STATE_ID = (
        SELECT STATE_ID 
        FROM STATES 
        WHERE STATE_NAME = 'CLOSED' 
         AND DOMAIN_ID = (
              SELECT DOMAIN_ID 
              FROM STATES a, 
               OBJECTS b 
              WHERE a.STATE_ID = b.STATE_ID 
               AND b.OBJECT_ID = OBJECTS.OBJECT_ID 
             ) 
       ) 
WHERE EXISTS (
       SELECT * 
       FROM STATES 
       WHERE STATE_NAME = 'CLOSED' 
         AND DOMAIN_ID = (
             SELECT DOMAIN_ID 
             FROM STATES a, 
               OBJECTS b 
             WHERE a.STATE_ID = b.STATE_ID 
               AND b.OBJECT_ID = OBJECTS.OBJECT_ID 
            ) 
       ); 
+0

你已经在功能上改变了OP想要做的事情。只有OBJECTS表的一个子集需要更新(OBJECTS_TO_UPDATE表中有OBJECT_ID的那些表) – MatBailie 2011-05-18 13:31:03

+0

@Dems:它应该高亮显示如何在范围内引用表,但为了完整性(和矫枉过正)我更新了我的答案。 – onedaywhen 2011-05-18 13:41:37

+0

嗯,WHERE子句不需要按照OPs? OBJECT_ID in(从OBJECTS_TO_UPDATE中选择不同的OBJECT_ID) ' – MatBailie 2011-05-18 13:42:49

0

SQL服务器的MS Access,(MySQL的?)解决方案:

我觉得这样做的伎俩。你可能想用SELECT *第一更换UPDATESET条款,并检查结果集看起来是正确的:

update o 
set STATE_ID = s_closed.STATE_ID 
from 
    Objects o 
     inner join 
    States s_current 
     on 
     o.STATE_ID = s.STATE_ID 
     inner join 
    States s_closed 
     on 
     s_current.DOMAIN_ID = s_closed.DOMAIN_ID and 
     s_closed.STATE_NAME = 'Closed' 
     inner join 
    OBJECTS_TO_UPDATE otu 
     on 
     otu.OBJECT_ID= o.OBJECT_ID 
+0

这应该在MS-SQL-Server中工作,但不在Oracle中(例如)。完全取决于OP使用的是什么RDBMS我猜... – MatBailie 2011-05-18 13:44:03

+0

@Dems - true,我会在顶部添加一个注释 - 但请注意,我们正在处理来自STATES表的两个不同行,并且我认为匹配OP在第一个查询中的内容 - 所以你的回答也需要一些工作:-) – 2011-05-18 13:46:35

0

不知道更多关于你的表的结构,我不能肯定是什么你需要的SQL。但是,子查询以获得新的STATE_ID能(如onedaywhen说)引用您正在更新的表...

例如...

update 
    OBJECTS 
set 
    STATE_ID = 
    (
     select 
     NEW_STATE.STATE_ID 
     from 
     STATES AS OLD_STATE 
     inner join 
     STATES AS NEW_STATE 
      ON NEW_STATE.DOMAIN_ID = OLD_STATE.DOMAIN_ID 
     where 
     OLD_STATE.STATE_ID = OBJECTS.STATE_ID 
     AND NEW_STATE.STATE_NAME = 'CLOSED' 
    ) 
where 
    OBJECT_ID in (select distinct OBJECT_ID from OBJECTS_TO_UPDATE) 

通过这种方式,可以确保子查询只返回OBJECTS表中任何给定记录的一个STATE_ID。