Почему не происходит сбой SQL Server, когда результат ОБНОВЛЕНИЯ неоднозначен? - PullRequest
4 голосов
/ 16 марта 2009

У меня есть две таблицы, место назначения для обновления:

create table dest (value int)
insert into dest values (0)

и источник:

create table source (value int)
insert into source values (4)
insert into source values (1)

Если я выполню этот запрос:

UPDATE dest SET value = (select value from source WHERE 1=1)

Сбой SQL Server:

Subquery returned more than 1 value. This is not permitted when 
the subquery follows =, !=, <, <= , >, >= ...

что идеально. Но если я выполню этот запрос:

UPDATE dest SET value = source.value FROM dest INNER JOIN Source ON 1=1 

... случайным образом выбирает одно из значений из источника и обновляет с ним dest.

Страшно? Есть ли объяснение этому?

Ответы [ 3 ]

11 голосов
/ 16 марта 2009

Да, причина, по которой ваш первый запрос терпит неудачу, не имеет ничего общего с оператором обновления, запускающим этот запрос:

select * from dest
where value = (select value from source)

Если у вас есть подзапрос, в котором используется любой из операторов, таких как =,! = И т. Д., Вы не можете вернуть более одного результата. Если вы хотите сказать, дайте мне все значения в dest, где совпадающее значение находится в источнике, то вы должны использовать предложение In:

select * from dest
where value in (select value from source)

Что касается вашей второй части вашего вопроса, то ячейка может иметь только одно значение, поэтому ваши действия заменяют ее снова и снова. Это совершенно верно.

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

2 голосов
/ 16 марта 2009

Oracle запрещает подобные запросы:

UPDATE dest SET value = source.value FROM dest INNER JOIN Source ON 1=1

, если таблица source не является таблицей key-preserved (т.е. вы присоединяете dest к некоторому полю из source, которое явно не объявлено UNIQUE (UNIQUE INDEX или PRIMARY KEY ).

Этот метод обеспечивает выбор не более одной строки из dest в представлении.

Если нет никаких ограничений UNIQUE, обновление все равно не будет выполнено, даже если в source.

нет действительных дубликатов.

SQL Server не имеет этого ограничения и просто обновляет первое значение во встречах, пропуская остальные.

Какое значение является первым, зависит от нескольких условий, включая метод соединения, выбранный оптимизатором.

0 голосов
/ 16 марта 2009

В первом примере подзапрос возвращает несколько строк, и обновление завершается неудачно. Во втором примере соединение успешно выполнено, поэтому обновление можно продолжить. Результаты непредсказуемы, потому что соединение не ограничено.

...