Рассмотрим этот очень простой оператор UPDATE, используя Northwind:
UPDATE Categories
SET Description = (
SELECT DISTINCT 'Anything'
FROM Employees
);
Сбой при ошибке «Операция должна использовать обновляемый запрос».
Простой движок базы данных Access не поддерживает синтаксис SQL-92 с использованием скалярного подзапроса в предложении SET
.
Механизм базы данных Access имеет собственный проприетарный синтаксис UPDATE..JOIN..SET
, но небезопасен, потому что, в отличие от скалярного подзапроса, он не требует однозначных значений. Если значения неоднозначны, то движок беззвучно «выбирает» один из них, и трудно (если не невозможно) предсказать, какое из них будет применено, даже если вы знали о проблеме.
Например, рассмотрим существующую таблицу Categories
в Northwind и следующую таблицу с ошибками (не) в качестве цели для обновления (глупо, но просто, чтобы ясно продемонстрировать проблему):
CREATE TABLE BadCategories
(
CategoryID INTEGER NOT NULL,
CategoryName NVARCHAR(15) NOT NULL
)
;
INSERT INTO BadCategories (CategoryID, CategoryName)
VALUES (1, 'This one...?')
;
INSERT INTO BadCategories (CategoryID, CategoryName)
VALUES (1, '...or this one?')
;
Теперь для UPDATE
:
UPDATE Categories
INNER JOIN (
SELECT T1.CategoryID, T1.CategoryName
FROM Categories AS T1
UNION ALL
SELECT 9 - T2.CategoryID, T2.CategoryName
FROM Categories AS T2
) AS DT1
ON DT1.CategoryID = Categories.CategoryID
SET Categories.CategoryName = DT1.CategoryName;
Когда я запускаю это, мне говорят, что две строки были обновлены, что забавно, потому что в таблице категорий есть только одна соответствующая строка. В результате таблица Categories
с CategoryID
теперь имеет '... или эту?' значение. Я подозреваю, что это была гонка, чтобы увидеть, какое значение записывается в таблицу последним.
Скалярный подзапрос SQL-92 является многословным, когда в SET
есть несколько предложений и / или предложение WHERE соответствует предложениям SET
, но, по крайней мере, устраняет неоднозначность (плюс приличный оптимизатор должен быть в состоянии обнаруживает, что подзапросы являются близкими совпадениями). В стандарт SQL-99 введено MERGE
, которое можно использовать для устранения вышеупомянутого повторения, но само собой разумеется, что Access также не поддерживает это.
Недостаточная поддержка ядром базы данных Access синтаксиса скалярных подзапросов в SQL-92 является для меня худшей «конструктивной особенностью» (читай «ошибка»).
Также обратите внимание, что собственный синтаксис UPDATE..JOIN..SET
ядра СУБД Access никоим образом не может использоваться с функциями набора («итоговые запросы» в Access-speak). См. Обновление запроса на основе итоговых ошибок запроса .