sqlmariadb

Rename values in one column, depending on the value in other column


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?


Solution

  • 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';
    

    Demo: https://dbfiddle.uk/tQNrSTC5