SQL - 返回最近的付款日期和金额

时间:2018-05-03 21:51:35

标签: sql oracle

我在Oracle中创建了以下查询,以便从客户返回最近的付款日期和相应的付款金额。它的工作原理是因为我没有包含Amount字段。如果我这样做,每个公司会产生多行。 非常感谢提前。

工作(但不包括最近的金额)

SELECT COMPANY_NAME, TERM_CODE, 
MAX(LAST_PYMT) AS LAST_PYMT_REC, 
AR_BALANCE, MAX_CREDIT_AR, OFFSET_BALANCE AS CREDITBAL_W_AP_OFFSETS 
FROM 
(
SELECT COMPANY_NAME,  s2.LAST_PYMT, s2.AMOUNT, 
CURRENT_BALANCE AS AR_BALANCE,
(CURRENT_BALANCE - AP_TOTAL) AS OFFSET_BALANCE,
TERM_CODES.TERM_CODE,
AP_TOTAL,
MAX_CREDIT AS MAX_CREDIT_AR
FROM COMPANIES s1
LEFT OUTER JOIN CTIRELAND.term_codes ON term_codes.tmc_auto_key = s1.tmc_auto_key

inner join
(
  select CR_DETAIL.ENTRY_DATE LAST_PYMT, MAX(CR_DETAIL.CRD_AUTO_KEY),
    CR_DETAIL.AMOUNT, CR_DETAIL.CMP_AUTO_KEY
  from CR_DETAIL
  GROUP BY CR_DETAIL.CRD_AUTO_KEY, CR_DETAIL.CMP_AUTO_KEY, CR_DETAIL.ENTRY_DATE, CR_DETAIL.AMOUNT
) s2
  on s1.CMP_AUTO_KEY = s2.CMP_AUTO_KEY 

  ORDER BY s1.company_name
  )
  GROUP BY COMPANY_NAME, AR_BALANCE, MAX_CREDIT_AR, OFFSET_BALANCE, TERM_CODE
  ORDER BY AR_BALANCE DESC

不工作(返回每家公司的每笔金额而不仅仅是最近的金额)  

SELECT COMPANY_NAME, TERM_CODE, 
MAX(LAST_PYMT) AS LAST_PYMT_REC, AMOUNT, 
AR_BALANCE, MAX_CREDIT_AR, OFFSET_BALANCE AS CREDITBAL_W_AP_OFFSETS 
FROM 
(
SELECT COMPANY_NAME,  s2.LAST_PYMT, s2.AMOUNT, 
CURRENT_BALANCE AS AR_BALANCE,
(CURRENT_BALANCE - AP_TOTAL) AS OFFSET_BALANCE,
TERM_CODES.TERM_CODE,
AP_TOTAL,
MAX_CREDIT AS MAX_CREDIT_AR
FROM COMPANIES s1
LEFT OUTER JOIN CTIRELAND.term_codes ON term_codes.tmc_auto_key = s1.tmc_auto_key

inner join ( select CR_DETAIL.ENTRY_DATE LAST_PYMT, MAX(CR_DETAIL.CRD_AUTO_KEY), CR_DETAIL.AMOUNT, CR_DETAIL.CMP_AUTO_KEY from CR_DETAIL GROUP BY CR_DETAIL.CRD_AUTO_KEY, CR_DETAIL.CMP_AUTO_KEY, CR_DETAIL.ENTRY_DATE, CR_DETAIL.AMOUNT ) s2 on s1.CMP_AUTO_KEY = s2.CMP_AUTO_KEY

ORDER BY s1.company_name ) GROUP BY COMPANY_NAME, AR_BALANCE, MAX_CREDIT_AR, OFFSET_BALANCE, TERM_CODE, AMOUNT ORDER BY AR_BALANCE DESC

2 个答案:

答案 0 :(得分:0)

尝试以下代码,希望它能解决您的要求。我添加了一个排名,根据最后一个付款日期查找排名,然后我在排名上过滤您的数据,这样您就可以得到所有其他列的排名=" 1"从下面的代码。

select COMPANY_NAME, TERM_CODE, LAST_PYMT LAST_PYMT_REC, AR_BALANCE, MAX_CREDIT_AR,CREDITBAL_W_AP_OFFSETS
(SELECT  COMPANY_NAME, TERM_CODE, LAST_PYMT LAST_PYMT_REC, AR_BALANCE, MAX_CREDIT_AR, OFFSET_BALANCE AS CREDITBAL_W_AP_OFFSETS,
        rank() over (partition by COMPANY_NAME, AR_BALANCE, MAX_CREDIT_AR, OFFSET_BALANCE, TERM_CODE order by last_pymt desc) rn 
FROM 
    (SELECT COMPANY_NAME,  s2.LAST_PYMT, s2.AMOUNT, CURRENT_BALANCE AS AR_BALANCE, (CURRENT_BALANCE - AP_TOTAL) AS OFFSET_BALANCE,
            TERM_CODES.TERM_CODE,AP_TOTAL,MAX_CREDIT AS MAX_CREDIT_AR
    FROM COMPANIES s1
    LEFT OUTER JOIN CTIRELAND.term_codes ON term_codes.tmc_auto_key = s1.tmc_auto_key
    inner join
    (
      select CR_DETAIL.ENTRY_DATE LAST_PYMT, MAX(CR_DETAIL.CRD_AUTO_KEY),
        CR_DETAIL.AMOUNT, CR_DETAIL.CMP_AUTO_KEY
      from CR_DETAIL
      GROUP BY CR_DETAIL.CRD_AUTO_KEY, CR_DETAIL.CMP_AUTO_KEY, CR_DETAIL.ENTRY_DATE, CR_DETAIL.AMOUNT
    ) s2
      on s1.CMP_AUTO_KEY = s2.CMP_AUTO_KEY 
      ORDER BY s1.company_name)
) m
where m.rn = 1
ORDER BY AR_BALANCE DESC;

答案 1 :(得分:0)

当编写一个与问题中的查询一样复杂的查询时,很容易出错(或两个)。由于我们手头没有任何真实的休息数据,我宁愿给你一个简化的例子,当你将所提出的原则应用到你自己的查询中时,应该允许你自己找到正确的解决方案。正如@Vivek所建议的那样,使用分析函数(参见documentationexamples)将是获得所需结果集的一种方法。

测试表

-- helper table
create table T
as
select 
  level as companyid
from dual
connect by level <= 4 ;

-- table used for queries
create table T2
as
select 
  A.companyid
, trunc( dbms_random.value * 1000 ) as amount
, to_date( trunc( dbms_random.value( 2446081, 2458243 ) ), 'J' ) paymentdate
from T A, T B ;

数据

SQL> select * from T2 order by companyid, paymentdate desc ;

COMPANYID  AMOUNT  PAYMENTDATE  
1          766     27-MAY-95 -- <- required 
1          198     12-APR-90    
1          554     05-AUG-89    
1          82      27-FEB-87    
2          195     07-AUG-07 -- <- required      
2          623     07-OCT-03    
2          903     01-NOV-93    
2          519     09-NOV-88    
3          561     27-JUN-97 -- <- required      
3          335     05-SEP-92    
3          327     25-JAN-87    
3          967     04-AUG-85    
4          623     10-APR-17 -- <- required      
4          912     24-FEB-12    
4          385     08-APR-01    
4          708     10-MAR-87 

16 rows selected. 

问题是:我们想要为每个公司提供最新的PAYMENTDATE,包括其AMOUNT - 类似于以下查询,这不起作用......

select 
  companyid
, max( paymentdate )
, amount               -- cannot get the amount of the last payment(date)
from T2
group by companyid ;
-- ORA-00979: not a GROUP BY expression

如果我们现在向GROUP BY子句添加更多列,我们会得到太多组(就像它一样)。当您刚刚将AMOUNT列添加到SELECT和GROUP BY子句时,就会发生这种情况。

-- if we code
-- ... group by companyid, paymentdate, amount
-- then we get all rows (again) -> no use
select 
  companyid
, max( paymentdate )
, amount              
from T2
group by companyid, paymentdate, amount ;

-- 16 rows selected. (output omitted)

使用分析函数允许我们通过编写(partition by ...)以不同的方式“分组”行。请注意,此查询中缺少GROUP BY子句。我们得到了所需的PAYMENTDATE等。

select distinct
  companyid
, max( paymentdate ) over ( partition by companyid ) mostrecentpayment
, first_value( amount ) over ( partition by companyid order by paymentdate desc ) amount
from T2 
order by companyid ;

-- result
COMPANYID  MOSTRECENTPAYMENT  AMOUNT  
1          27-MAY-95          766     
2          07-AUG-07          195     
3          27-JUN-97          561     
4          10-APR-17          623 

使用@ Vivek的方法,对于相同的测试表(结果集与上面相同):

select 
  companyid
, paymentdate
, amount
from (
  select 
    companyid
  , paymentdate
  , rank() over ( partition by companyid order by paymentdate desc ) rank_
  , amount               
  from T2 
) where rank_ = 1 ;

COMPANYID  PAYMENTDATE  AMOUNT  
1          27-MAY-95    766     
2          07-AUG-07    195     
3          27-JUN-97    561     
4          10-APR-17    623 

使用Oracle 12c进行测试。注意:T2中的值是随机的!