Могу ли я обновить несколько записей одним оператором SQL, где значение обновления зависит от обновляемой записи? - PullRequest
1 голос
/ 18 мая 2011

Учитывая, что есть 2 таблицы:

  1. STATES (содержит список доступных состояний) - ключевое поле = STATE_ID. Другой ключ - DOMAIN_ID, STATE_NAME. Таким образом, существуют записи с одинаковым STATE_NAME, но с другим DOMAIN_ID.
  2. OBJECTS (содержит список всех объектов, каждый со своим состоянием) - поле ключа = OBJECT_ID. Также содержит поле STATE_ID.

Предположим, у меня есть список из примерно 1000 объектов, которые необходимо обновить до состояния "ЗАКРЫТО" в соответствующих доменах.

Для одного объекта (скажем, 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

Можно ли использовать один оператор для обновления более одного объекта? Суть проблемы, кажется, в том, что я не могу обойти определение OBJECT_ID в двух местах в операторе 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 in
    (
      select distinct OBJECT_ID from OBJECTS_TO_UPDATE
    )
  )
) where OBJECT_ID in (select distinct OBJECT_ID from OBJECTS_TO_UPDATE)

Может ли кто-нибудь дать мне подсказку о том, что я мог бы сделать, чтобы обойти это?

Спасибо.

Ответы [ 3 ]

0 голосов
/ 18 мая 2011

SQL Server, MS Access , (MySQL?) Решение:

Я думаю, что это помогает.Возможно, вы захотите сначала заменить предложения UPDATE и SET на SELECT * и убедиться, что набор результатов выглядит правильно:

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 голосов
/ 18 мая 2011

Не зная больше о структуре ваших таблиц, я не могу быть уверен, какой SQL вам нужен.Но подзапрос, чтобы получить новый STATE_ID, может (как было сказано ранее) ссылаться на обновляемую таблицу ...

Например ...

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)

Таким образомможет гарантировать, что подзапрос возвращает только один STATE_ID для любой данной записи в таблице OBJECTS.

0 голосов
/ 18 мая 2011

Вы можете использовать имя таблицы ОБЪЕКТЫ, потому что оно находится в области действия, например.

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
                                      )
                 );
...