#sql #firebird #execute
#sql #firebird #выполнить
Вопрос:
Я еще не использовал execute block в Firebird, но изо всех сил пытаюсь научиться его использовать.
Я пытаюсь извлечь уроки из простого примера, а затем перейду к более сложной ситуации.
Предположим, у меня есть 2 таблицы, как показано ниже:
------------ ------
| Clientcode | name |
------------ ------
| 123 | A |
| 234 | B |
------------ ------
---------- ------------ ---------
| order_id | clientcode | value |
---------- ------------ ---------
| 12 | 234 | 10,00 |
| 13 | 123 | 20,00 |
| 14 | 123 | 10,00 |
---------- ------------ ---------
У меня есть следующий код.
execute block returns (client integer,amount double)
as
declare variable client_code integer;
begin
for
select clientcode from clients
into : client_code
do
begin
select :client_code,sum(value) from orders group by 1
into :client, :order_id;
end
end
В принципе, я хочу для каждого клиента в таблице client вычислить сумму заказов в таблице orders. Я знаю, что в этом случае нет необходимости выполнять блок, но на простом примере я мог бы лучше понять это.
------------- --------
| client_code | amount |
------------- --------
| 123 | 30 |
| 234 | 10 |
------------- --------
Каков правильный синтаксис?
Комментарии:
1. начните с чтения о хранимых процедурах . По сути, EB — это одноразовый безымянный SP. Хранимые процедуры были в Interbase / Firebird десятилетиями, и исторически о них много информации. В книгах, на форумах, в часто задаваемых вопросах, везде. Когда вы упрощаете работу с SPS, все EBS одинаковы, но без имен и без постоянства. Так просто.
Ответ №1:
В вашем коде не хватает нескольких вещей:
- Вам нужно
where
предложение -при выборе fromorders
, чтобы ограничить его только строками текущего клиента - Вам нужно вывести сумму в
amount
, а не в несуществующую переменнуюorder_id
- Вам нужно добавить
suspend
для вывода строку (в противном случае блок execute может выдавать только одну строку с присвоенными последними значениями). - (необязательно) Вам не нужна переменная
client_code
, когдаclient
она выполняет ту же цель
Результирующий код будет выглядеть примерно так (обратите внимание, что я использовал decimal(18,2)
вместо double precision
, используя числовые типы точной точности, например decimal
, лучший выбор для денежных значений):
execute block returns (client_code integer,amount decimal(18,2))
as
begin
for select clientcode from clients
into client_code
do
begin
select sum(amount) from orders where clientcode = :client_code
into amount;
suspend;
end
end
Это эквивалентно следующему запросу:
select clients.clientcode as client_code, sum(orders.amount) as amount
from clients
left join orders on clients.clientcode = orders.clientcode
group by clients.clientcode
Смотрите также этот dbfiddle.
Имейте в виду, execute block
по сути, это хранимая процедура Firebird, которая не сохраняется. Функция execute block
с a suspend
ведет себя как выбираемая процедура, которая может выдавать ноль или более строк, а одна без suspend
ведет себя как исполняемая процедура, которая может выдавать только одну строку.