Your problem cannot be resolved with crosstab because the list of the columns in the result must be dynamically calculated against the rows of the Table 2 which may be updated at any time.
A solution exists to solve your problem. It consists of :
- creating a
composite type dynamically with the list of expected
column labels according to the Table 2 status within a plpgsql
procedure
- calling the procedure before executing the query
- building the query by grouping the Table 2 rows by
Order_id and Order_line_id so that to aggregate these rows into the taget row structure
- converting the target rows into
json objects and displaying these json objects in the final status by using the json_populate_record function and the composite type
Step 1 :
CREATE OR REPLACE PROCEDURE composite_type() LANGUAGE plpgsql AS $$
DECLARE
column_list text ;
BEGIN
SELECT string_agg(m.name || ' text', ', ')
INTO column_list
FROM
( SELECT Type || generate_series(1, max(count)) AS name
FROM
( SELECT lower(Type) AS type, count(*)
FROM table_2
GROUP BY Order_Id, Order_line_id, Type
) AS s
GROUP BY Type
) AS m ;
DROP type IF EXISTS composite_type ;
EXECUTE 'CREATE type composite_type AS (' || column_list || ')';
END ; $$
Step 2 :
CALL composite_type() ;
Step 3,4 :
SELECT t.Order_Id, t.Order_line_id
, (json_populate_record(null :: composite_type, json_object_agg(t.label, t.Amount))).*
FROM
( SELECT Order_Id, Order_line_id
, lower(Type) || (row_number() OVER (PARTITION BY Order_Id, Order_line_id, Type)) :: text AS label
, Amount
FROM table_2
) AS t
GROUP BY t.Order_Id, t.Order_line_id ;
The final result is :
| order_id |
order_line_id |
kiwi1 |
orange1 |
orange2 |
apple1 |
apple2 |
| 1 |
1 |
45 |
32 |
null |
0 |
null |
| 1 |
2 |
null |
98 |
76 |
12 |
null |
| 1 |
1001 |
null |
null |
null |
60 |
90 |
see the full test result in dbfiddle