I just want to thank anyone that would like to spent some of his time to address my question. I just want to mention that I am not so good at SQL.
Description of the problem.
I have Orders table where each order has price, userId who made the order and date of the order.
Also I have payments table where there is userid, date and payment amount.
All I need is getting the order and payments for each user grouped by years (I have a case to group by months but lets put it aside for now)
The problem arise when the client has no orders for 2024 but has payments for the period. than those rows are skipped.
Putting the sql query I use.
SELECT order_data.user_id,
order_data.username,
order_data.customer_email,
order_data.customer_mobile,
order_data.year as year,
order_data.orders_amount as order_amount,
COALESCE(payment_data.payment_amount, 0) as payment_amount,
COALESCE(payment_amount - orders_amount, 0 - orders_amount) as balance,
order_data.latest_order_date,
payment_data.latest_payment_date
FROM (SELECT orders.user_id,
orders.username,
orders.customer_email,
orders.customer_mobile,
date_part('year', orders.status_change_date) as year,
sum(orders.amount) as orders_amount,
max(orders.create_date) as latest_order_date
from arag_araqum.orders orders
GROUP BY orders.user_id, orders.username, orders.customer_email, orders.customer_mobile, year) as order_data
FULL JOIN (Select payment.user_id,
date_part('year', payment.create_date) as year,
sum(payment.amount) as payment_amount,
max(payment.create_date) as latest_payment_date
from arag_araqum.payments as payment
GROUP BY user_id, year) as payment_data
ON order_data.user_id = payment_data.user_id
AND
order_data.year = payment_data.year;
ORDERS DB
create table orders
(
id bigint generated always as identity
constraint order_pkey
primary key,
user_id text not null,
username text not null,
customer_email text not null,
customer_mobile text,
amount bigint,
create_date date,
status_change_date date
);
PAYMENTS TABLE
create table payments
(
id bigint generated always as identity
constraint payment_pkey
primary key,
user_id text not null,
amount bigint,
create_date date
);
The case is when user A has no orders for 2024 but has payments made
3
Answers
Solution to your problem:
It is hard to answer without some sample data and expected result from that data, so I’ll try to show what could be the issue you are facing – with some sample data like here:
With orders and payments from above – if we do the FULL JOIN as in your query…
… the result would be …
As I understood the question it looks like you want your data of all orders/payments with the balance grouped by months (here by years) – regardless if in any particular month (year) there were both orders and payments or just one of them.
One option to do it (with sample data from above) is to group the orders and payments separately and do the UNION ALL. After that just aggregate and group by the resultset of the unioned data:
And if you want to see all transactions with cumulative values partitioned by user and year (added total user balance too) then:
There are several ways to perform the desired aggregations. The following demonstrates an approach using
FULL JOIN
without subqueries. The CTEs,orders
andpayments
, are proxies for the actual tables. Note that the user/customer details have been left out oforders
. This has been done because those details should be stored in separate tables that are referenced inorders
so that the relations are in third-normal form instead of replicating the data across multiple rows.Running the above produces the following output: