Можем ли мы уменьшить избыточность между двумя подзапросами в операторе обновления? - PullRequest
0 голосов
/ 24 июня 2018

Из концепции системы баз данных

Предположим, у нас есть отношение fund_received (dept_name, amount), которое сохраняет средства (например, электронным переводом) для каждого из набор отделов. Предположим теперь, что мы хотим добавить суммы к остатки соответствующих отделов бюджетов. Для того, чтобы использовать оператор SQL для выполнения этой задачи, мы должны выполнить посмотреть на соотношение полученных средств для каждого кортежа в отдел отношений. Мы можем использовать подзапросы в предложении update для выполнить эту задачу следующим образом: для простоты мы предполагаем, что полученные фоновые отношения содержат не более одного кортежа для каждого отдел.

update department set budget = budget +
(select amount
from funds_received
where funds_received.dept_name = department.dept_name)
where exists(
select *
from funds_received
where funds_received.dept_name = department.dept_name);

Обратите внимание, что условие в предложении where обновления гарантирует, что обновляются только счета с соответствующими кортежами в полученных средствах, в то время как подзапрос в предложении set вычисляет сумму, которая будет добавлен в каждый такой отдел.

Мне было интересно, зачем нам нужен пункт where, чтобы сначала проверить, получил ли департамент какой-либо фонд?

Два подзапроса в основном одинаковы и кажутся избыточными.

Не может ли следующее без предложения where работать одинаково?

 update department set budget = budget +
 (select amount
 from funds_received
 where funds_received.dept_name = department.dept_name)

Если в отделе нет полученного фонда, amount будет нулевым, а budge + ... не будет работать?

Меня интересуют решения либо в стандарте SQL, либо в PostgreSQL.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 24 июня 2018

Вы можете оставить внешнее предложение WHERE, если обрабатываете NULL s, например с coalesce().

UPDATE department
       SET budget = budget
                    +
                    coalesce((SELECT amount
                                     FROM funds_received
                                     WHERE funds_received.dept_name = department.dept_name), 0);

Это гарантирует, что если отдел не получит никаких средств, не будет возвращено NULL, что могло бы также дать дополнительный доход NULL (это может зависеть от СУБД, что происходит в таком случае). coalesce() превратит NULL в 0, нейтральный элемент сложения, поэтому бюджет останется без изменений.

(Предполагая, что funds_received.amount не может быть NULL. Если это было NULL, то coalesce() не может "знать", если NULL существует, потому что запись не была найдена или потому что amount на самом деле было NULL. В случае amount на самом деле NULL, исходный запрос добавит NULL к бюджету, мой запрос добавит 0. Таким образом, запросы не были эквивалентны в этом случае Но я думаю, что весьма вероятно, что автор книги имел в виду такое неявное ограничение NOT NULL на funds_received.amount.

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

0 голосов
/ 24 июня 2018

Вам нужно предложение where, если ничего не найдено.Если это так, то условие set (как написано) вернет NULL - возможно, это плохо.

Но у Postgres есть лучшее решение, использующее from:

update department d
    set budget = d.budget + fr.amount
from funds_received fr
where fr.dept_name = d.dept_name;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...