Обучение использованию execute block в Firebird на простом примере

#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:

В вашем коде не хватает нескольких вещей:

  1. Вам нужно where предложение -при выборе from orders , чтобы ограничить его только строками текущего клиента
  2. Вам нужно вывести сумму в amount , а не в несуществующую переменную order_id
  3. Вам нужно добавить suspend для вывода строку (в противном случае блок execute может выдавать только одну строку с присвоенными последними значениями).
  4. (необязательно) Вам не нужна переменная 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 ведет себя как исполняемая процедура, которая может выдавать только одну строку.