PostgreSQL MERGE TO Reconcile Cash Register Sales Data Part 1
I hoped to present the following at the PostgreSQL Conference 2025 in March. But I can not make it to Orlando for this wonderful event (Please attend if you can! It is a fantastic event). Cash Register information is vital to retail businesses and it is often processed one line item at a time (pronounced 'S-L-O-W'). MERGE was added a few years ago to PostgreSQL's arsenal. It is powerful and easy to use.
The Cash Register
The next time you are handed a receipt from a cash register, take the time to examine all the information on it. Time, date, location, total, line items, and possibly other information essential to the vendor's operations are on that slip of paper. There may be information not on the sales receipt collected for processing. Now imagine you are a major fast-food restaurant with tens of thousands of cash registers or more. All that data needs to be collected, transmitted, and processed. It is easy to see how efficiency is important.
MERGE
The manual page describes the function of MERGE distinctly as MERGE performs actions that modify rows in the target table identified as target_table_name, using the data_source. MERGE provides a single SQL statement that can conditionally INSERT, UPDATE or DELETE rows, a task that would otherwise require multiple procedural language statements. In the examples below the data source is the data from the cash register and the target table is the sales table.
Our simple example uses the following table for cash register data. We will assume that each cash register in our imaginary fast-food chain has a unique identification number.
CREATE TABLE
demo=# insert into register values (1,101,19.99);
INSERT 0 1
demo=#
First Merge
Second Merge
If we run the same SQL code again, the results look a little different even if the data in the ledger tables does not change. This time there IS a match between the two tables. Later you will see how to right WHEN MATCH clauses.
using register r
on l.id = r.id
WHEN NOT MATCHED THEN
insert (id, tx_id, total_register, misc)
values (r.id, r.tx_id, r.amount, 0)
RETURNING merge_action(), l.*;
merge_action | id | tx_id | total_register | misc
--------------+----+-------+----------------+------
(0 rows)
MERGE 0
demo=# select * from ledger;
id | tx_id | total_register | misc
----+-------+----------------+------
1 | 101 | $19.99 | 0
(1 row)
demo=#
Sometimes the same data is applied twice which is a disaster in many cases. But in this case, there was no action taken.
What is needed is to compare the transaction IDs along with the register IDs to make sure we do not record twice the same line of data. heck, we probably in real life want a unique key made with the store number and the register id.
Next Time
I am trying to keep these blogs short, if not sweet. And this one went on a bit longer than I thought. Next time we will look at more MERGE() functionality and explore the logic of making matches to optimize the performance of the query.
Comments
Post a Comment