I have two tables with orders and parcels in MariaDB:
Orders
id | order_id | customer | payment |
---|---|---|---|
1 | 100 | customer 1 | COD |
2 | 101 | customer 2 | paid |
3 | 102 | customer 3 | COD |
4 | 103 | customer 4 | COD |
5 | 104 | customer 5 | paid |
Parcels
id | order_id | parcels | weight | width | height | length |
---|---|---|---|---|---|---|
1 | 100 | 1 | 5 | 10 | 10 | 20 |
2 | 101 | 1 | 5 | 10 | 10 | 20 |
3 | 102 | 1 | 5 | 10 | 10 | 20 |
4 | 103 | 1 | 10 | 20 | 20 | 30 |
5 | 103 | 1 | 15 | 30 | 30 | 40 |
6 | 103 | 1 | 20 | 20 | 20 | 40 |
7 | 104 | 1 | 12 | 32 | 32 | 42 |
8 | 104 | 1 | 18 | 40 | 40 | 50 |
9 | 104 | 1 | 25 | 40 | 45 | 50 |
and the following view:
CREATE OR REPLACE VIEW SHIPPING_LABELS AS SELECT
DISTINCT(ORD.order_id) AS order_id,
ORD.customer AS customer,
ORD.payment AS payment
FROM orders ORD
LEFT JOIN parcels PAR ON (ORD.order_id = PAR.order_id)
ORDER BY ORD.order_id DESC
This view generates the following result:
order_id | customer | payment |
---|---|---|
100 | customer 1 | COD |
101 | customer 2 | paid |
102 | customer 3 | COD |
103 | customer 4 | COD |
104 | customer 5 | paid |
But, depending on the payment type, I need this result:
order_id | customer | payment |
---|---|---|
100 | customer 1 | COD |
101 | customer 2 | paid |
102 | customer 3 | COD |
103 | customer 4 | COD |
104_1 | customer 5 | paid |
104_2 | customer 5 | paid |
104_3 | customer 5 | paid |
So, if there are more than 1 parcels and the payment is COD, it should be 1 row (DISTINCT). However, if the order is paid, the order_id should be renamed to _[1-...].
Is something like that possible in pure SQL?
Well, your current result is just select * from orders
. It makes no sense to outer join a table, but not select anything from it and then use DISTINCT
to remove the duplicate rows again created by the join.
What you want is to duplicate order rows in case the payment equals 'paid', so change the outer join accordingly. Then use window functions (COUNT OVER
and ROW_NUMBER OVER
) to decide whether to attatch numbers to the original order numbers and to get these numbers. Use a CASE
expression to decide which kind of order number to display.
CREATE OR REPLACE VIEW shipping_labels AS
SELECT
CASE WHEN COUNT(*) OVER (PARTITION BY o.order_id) > 1 THEN
CONCAT(p.order_id, '_', ROW_NUMBER() OVER (PARTITION BY p.order_id ORDER BY p.id))
ELSE
o.order_id
END AS order_id,
o.customer,
o.payment
FROM orders o
LEFT JOIN parcels p ON p.order_id = o.order_id AND o.payment = 'paid';