Home > Software design >  ORACLE SQL - multiple JOINs from same table
ORACLE SQL - multiple JOINs from same table

Time:12-15

I have data related material transactions in one table and log history header data related to materials is in another table and detailed log history data in third table. I'm trying to get different status update dates matched to material table but I get duplicate rows for one material transaction

Original material transaction table:

ORDER_NO MATERIAL QTY
0001 MAT01 2
0002 MAT02   5

Original Log History Header transaction table:

ORDER_NO LOG_ID
0001 1001
0001 1002

Status code 1 refers to Opened and code 2 to Closed

Detailed Log History table:

LOG_ID STATUS_CODE DATE
1001 1 11/12/2021
1002 2   15/12/2021

With following SQL query:

SELECT 
       TO_CHAR (m.order_no) order_no,
       m.material,
       a.date opened_date,
       ab.closed_date
  FROM MATERIAL_TRANSACTIONS m
       INNER JOIN HISTORY_LOG t
          ON m.ORDER_NO = t.ORDER_NO
       INNER JOIN HISTORY_LOG_DETAILED a
          ON     t.LOG_ID = a.LOG_ID
             AND a.STATUS_CODE = '1'
       INNER JOIN HISTORY_LOG_DETAILED ab
          ON     t.LOG_ID = ab.LOG_ID
             AND ab.STATUS_CODE = '2'

I get following result:

ORDER_NO MATERIAL QTY OPENED_DATE CLOSED_DATE
0001 MAT01 2 11/12/2021
0001 MAT01   2 15/12/2021

And I would like to get the status dates to the same row as below:

ORDER_NO MATERIAL QTY OPENED_DATE CLOSED_DATE
0001 MAT01 2 11/12/2021 15/12/2021

I would appreciate all the help I can get and am very sorry if there already is topic for similar issue.

CodePudding user response:

Your problem occurs because you join the history table, which holds 2 records for the order. You could flatten this if you use 2 inline tables that hold exactly 1 record.

with opened_dates as (
  select h.order_id, d.date
  from history h
  inner join details d on h.log_id = d.log_id and d.status_code = '1'
), closed_dates as (
  select h.order_id, d.date
  from history h
  inner join details d on h.log_id = d.log_id and d.status_code = '2'
)
select to_char (m.order_no) order_no,
       m.material,
       o.date opened_date,
       c.date closed_date
from material_transactions m
join opened_dates o on m.order_no = o.order_no
join closed_dates c on m.order_no = c.order_no
;

CodePudding user response:

Just an idea :

I joined HISTORY_LOG and HISTORY_LOG_DETAILED tables to get dates for specific status, and set as OPENED_DATE and CLOSED_DATE (if status 1 , then opened date is DATE column, otherwise set it as 01.01.0001)

After that grouped those records by ORDER_NO and maxed the date values to get actual OPENED_DATE and CLOSED_DATE .

Finally joined this subquery with MATERIAL_TRANSACTIONS table :

SELECT 
       TO_CHAR (M.ORDER_NO) ORDER_NO,
       M.MATERIAL,
       QTY,
       L_T.OPENED_DATE,
       L_T.CLOSED_DATE
  FROM MATERIAL_TRANSACTIONS M  
  INNER JOIN 
  (
  SELECT  L.ORDER_NO , 
 MAX( CASE WHEN LD.STATUS_CODE = 1 THEN LD.DATE ELSE TO_DATE('01.01.0001','dd.mm.yyyy')  END ) OPENED_DATE
MAX( CASE WHEN LD.STATUS_CODE = 2 THEN LD.DATE ELSE TO_DATE('01.01.0001','dd.mm.yyyy')  END ) CLOSED_DATE 
   FROM 
  HISTORY_LOG L 
  INNER JOIN HISTORY_LOG_DETAILED LD ON LD.LOG_ID = L.LOG_ID
 GROUP BY L.ORDER_NO
 ) L_T on L_T.ORDER_NO = M.ORDER_NO

Note: I didnt test it. So there can be small syntax errors. Please check it and for better help add a fiddle so i can test my query

  • Related