I haven’t used yet execute block in Firebird, but Im struggling to learn how to use it.
I am trying to learn from a simple example and then will expand to a more complex situation.
Suppose I have 2 tables like below:
+------------+------+ | Clientcode | name | +------------+------+ | 123 | A | | 234 | B | +------------+------+
+----------+------------+---------+ | order_id | clientcode | value | +----------+------------+---------+ | 12 | 234 | 10,00 | | 13 | 123 | 20,00 | | 14 | 123 | 10,00 | +----------+------------+---------+
I have the following code.
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
Basically, I want for every client in the client table to calculate the sum of the orders in the orders table. I know that it is not necessary execute block in this case, but with a simple example I might be able to understand it better.
+-------------+--------+ | client_code | amount | +-------------+--------+ | 123 | 30 | | 234 | 10 | +-------------+--------+
What is the correct syntax?
Advertisement
Answer
There are a few things missing in your code:
- You need a
where
-clause when selecting fromorders
to limit it to only the rows of the current client - You need to output the sum to
amount
, not to the non-existent variableorder_id
- You need to add
suspend
to output a row (otherwise an execute block can only produces a single row, with the last values assigned). - (optional) You don’t need the variable
client_code
whenclient
fulfills the same purpose
The resulting code would be something like (note that I used decimal(18,2)
instead of double precision
, using exact precision numeric types like decimal
is a better choice for money values):
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
This is the equivalent of the following query:
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
See also this dbfiddle.
Keep in mind, execute block
is essentially a Firebird stored procedure that isn’t stored. An execute block
with a suspend
behaves as a selectable procedure which can produce zero or more rows, and one without suspend
behaves as an executable procedure which can produce one row only.