Oracle加入表

时间:2017-04-06 16:14:05

标签: oracle join

我有以下格式的两张表。

TABLE1

SMUN_FNL,START_DTE    
111     , 07/10/2011    
111     , 28/07/2015

TABLE2

SMUN,BASE_YMD    
111 ,30/09/2011    
111 ,30/12/2011    
111 ,16/07/2015    
111 ,01/02/2014

我想将Table1连接到Table2,以便对于TABLE1中的每条记录

TABLE1.SMUN_FNL = TABLE2.SMUN 
AND TABLE2.BASE_YMD <= TABLE1.START_DTE 

即。为了匹配SMUN,它应该在 START_DTE之前拾取最近的 BASE_YMD

表2可能有也可能没有匹配的SMUN或SMUN记录,其中包含START_DTE之前的日期。 查询应返回与TABLE1相同数量的记录。 (表1左边加入TABLE2我猜)

输出

SMUN_FNL|START_DTE |BASE_YMD    
111     |07/10/2011|30/09/2011    
111     |28/07/2015|16/07/2015

我像这样加入

TABLE1.SMUN_FNL = TABLE2.SMUN_ID 
AND TABLE1.START_DTE <= TABLE2.BASE_YMD

然而,当两条记录都满足TABLE1.START_DTE <= TABLE2.BASE_YMD条件时,它会记录两条记录的07/10/2011日期。

任何帮助表示赞赏。 感谢

2 个答案:

答案 0 :(得分:1)

Answering based on the comment below "I need the nearest table2.base_ymd prior to table1.start_dte from table2" and a new business requirement "Table2 may or may not have a matching SMUN, or SMUN record with date before the START_DTE. The query should return same number of records as TABLE1":

SELECT t1.SMUN_FNL,
  TO_CHAR(t1.START_DTE, 'DD/MM/YYYY') AS START_DTE,
  TO_CHAR(t2.BASE_YMD, 'DD/MM/YYYY') AS BASE_YMD
FROM 
  TABLE1 t1
  LEFT OUTER JOIN
  (
    SELECT *
    FROM
    TABLE2 t2
    INNER JOIN
    (
      SELECT t1.SMUN_FNL, t1.START_DTE, MIN(t1.START_DTE-t2.BASE_YMD) AS MIN_DIFF
      FROM TABLE1 t1 INNER JOIN TABLE2 t2
        ON t1.SMUN_FNL = t2.SMUN 
        AND t2.BASE_YMD <= t1.START_DTE
      GROUP BY t1.SMUN_FNL, t1.START_DTE
    ) t3
    ON t2.SMUN = t3.SMUN_FNL
  ) t2
  ON t1.SMUN_FNL = t2.SMUN
    AND t2.BASE_YMD <= t1.START_DTE
    AND t1.START_DTE = t2.START_DTE
    AND t1.START_DTE-t2.BASE_YMD = t2.MIN_DIFF  

答案 1 :(得分:1)

测试:

假设

  • table1 SMUN_FNL和Start_date是UNIQUE:意味着不会重复相同smun_FNL的相同日期。
  • Start_DTE和Base_YMD是日期。对于按日期排序的逻辑(减去日期并返回具有“最低”差异的那个“),如果不是,则需要将它们转换为日期。

我们在这里做的是使用一个名为row_number()的窗口函数,对第一个表日期减去第二个表日期,得到一个以天为单位的数值,其中最低值是每个组中的第一行数。然后我们只保留每个分区的第一行(SMUN_FNL,Start_DTE组合)。

--test data
with table1(SMUN_FNL,START_DTE ) as (
SELECT 111, to_date('07/10/2011','dd/mm/yyyy') from dual union all
SELECT 112, to_date('07/10/2011','dd/mm/yyyy') from dual union all
SELECT 111, to_date('28/07/2015','dd/mm/yyyy') from dual),
table2 (SMUN,BASE_YMD) as     (
SELECT 112 ,to_date('07/11/2011','dd/mm/yyyy') FROM DUAL UNION ALL
SELECT 111 ,to_date('30/09/2011','dd/mm/yyyy') FROM DUAL UNION ALL
SELECT 111 ,to_date('30/12/2011','dd/mm/yyyy') FROM DUAL UNION ALL
SELECT 111 ,to_date('16/07/2015','dd/mm/yyyy') FROM DUAL UNION ALL
SELECT 111 ,to_date('01/02/2014','dd/mm/yyyy') FROM DUAL), 

--Begin part you need
cte as (
SELECT T1.SMUN_FNL
     , T1.START_DTE
     , T2.BASE_YMD
     , row_number() over (PARTITION BY SMUN_FNL, Start_DTE 
                          ORDER BY start_DTE-BASE_YMD asc) RN
FROM Table1 T1
LEFT JOIN Table2  T2
 on T1.SMUN_FNL = T2.SMUN
and T1.START_DTE >= T2.BASE_YMD)

SELECT SMUN_FNL, Start_DTE, Base_YMD 
FROM CTE 
WHERE RN = 1

收率:

SMUN_FNL START_DTE  BASE_YMD    RN
111     07-OCT-11   30-SEP-11   1
111     28-JUL-15   16-JUL-15   1
112     07-OCT-11               1

外部应用连接也可以在这里完成这个技巧但是我不确定你的oracle版本和窗口函数已经存在了几年了。