【问题标题】:SQL - Returning recent payment date and amountSQL - 返回最近的付款日期和金额
【发布时间】:2018-10-14 07:35:47
【问题描述】:

我在 Oracle 中创建了以下查询,以返回客户最近的付款日期和相应的付款金额。它有效,因为我没有包括金额字段。如果我这样做,它会导致每个公司出现多行。 非常感谢。

有效(但不包括最近的金额)

选择 COMPANY_NAME、TERM_CODE、
MAX(LAST_PYMT) 作为 LAST_PYMT_REC,
AR_BALANCE、MAX_CREDIT_AR、OFFSET_BALANCE 作为 CREDITBAL_W_AP_OFFSETS
从
(
选择公司名称,s2.LAST_PYMT,s2.AMOUNT,
CURRENT_BALANCE 作为 AR_BALANCE,
(CURRENT_BALANCE - AP_TOTAL) 作为 OFFSET_BALANCE,
TERM_CODES.TERM_CODE,
AP_TOTAL,
MAX_CREDIT AS MAX_CREDIT_AR
来自公司 s1
左外连接 CTIRELAND.term_codes ON term_codes.tmc_auto_key = s1.tmc_auto_key

内部联接
(
  选择 CR_DETAIL.ENTRY_DATE LAST_PYMT, MAX(CR_DETAIL.CRD_AUTO_KEY),
    CR_DETAIL.AMOUNT、CR_DETAIL.CMP_AUTO_KEY
  来自 CR_DETAIL
  按 CR_DETAIL.CRD_AUTO_KEY、CR_DETAIL.CMP_AUTO_KEY、CR_DETAIL.ENTRY_DATE、CR_DETAIL.AMOUNT 分组
) s2
  在 s1.CMP_AUTO_KEY = s2.CMP_AUTO_KEY

  由 s1.company_name 订购
  )
  GROUP BY COMPANY_NAME、AR_BALANCE、MAX_CREDIT_AR、OFFSET_BALANCE、TERM_CODE
  ORDER BY AR_BALANCE DESC

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

选择 COMPANY_NAME、TERM_CODE、
MAX(LAST_PYMT) AS LAST_PYMT_REC,AMOUNT,
AR_BALANCE、MAX_CREDIT_AR、OFFSET_BALANCE 作为 CREDITBAL_W_AP_OFFSETS
从
(
选择公司名称,s2.LAST_PYMT,s2.AMOUNT,
CURRENT_BALANCE 作为 AR_BALANCE,
(CURRENT_BALANCE - AP_TOTAL) 作为 OFFSET_BALANCE,
TERM_CODES.TERM_CODE,
AP_TOTAL,
MAX_CREDIT AS MAX_CREDIT_AR
来自公司 s1
左外连接 CTIRELAND.term_codes ON term_codes.tmc_auto_key = s1.tmc_auto_key

内连接 ( 选择 CR_DETAIL.ENTRY_DATE LAST_PYMT, MAX(CR_DETAIL.CRD_AUTO_KEY), CR_DETAIL.AMOUNT、CR_DETAIL.CMP_AUTO_KEY 来自 CR_DETAIL 按 CR_DETAIL.CRD_AUTO_KEY、CR_DETAIL.CMP_AUTO_KEY、CR_DETAIL.ENTRY_DATE、CR_DETAIL.AMOUNT 分组 ) s2 在 s1.CMP_AUTO_KEY = s2.CMP_AUTO_KEY

按 s1.company_name 订购 ) GROUP BY COMPANY_NAME、AR_BALANCE、MAX_CREDIT_AR、OFFSET_BALANCE、TERM_CODE、AMOUNT ORDER BY AR_BALANCE DESC

【问题讨论】:

  • 在所选列的列表中使用sum(AMOUNT),而不是AMOUNT 是否可以满足您的需求?
  • @SQLUSER999 尝试仅选择 MAX(LAST_PYMT) AS LAST_PYMT_REC, AMOUNT 并检查您是否获得预期结果

标签: sql oracle


【解决方案1】:

在编写与您的问题一样复杂的查询时,很容易出错(或两个)。由于我们手头没有任何真实的剩余数据,我宁愿给您一个简化的示例,当您将提出的原则应用于您自己的查询时,应该可以让您自己找到正确的解决方案。正如@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. 

问题是:我们想要每个 COMPANY 的最新 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)

使用分析函数允许我们以不同的方式“分组”行,通过写入(按...分区)。请注意,此查询中缺少 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 中的值是随机的!

【讨论】:

  • Stefan,非常感谢您的详细解释。在它和对 Vivek 响应的轻微修改之间,我能够解决这个问题。再次感谢您的详细解释,以后我会使用解析函数!
  • 感谢您的反馈!干杯。
【解决方案2】:

试试下面的代码,希望它能解决你的要求。我添加了一个排名,该排名根据最后付款日期找到排名,然后我根据排名过滤您的数据,以便您从下面的代码中获得排名 =“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;

【讨论】:

  • Vivek,我在您的第一个 Select 子句和第二个 Select 子句中添加了“金额”(我认为您忽略了这些)。无论如何,您的代码完美地解决了我遇到的问题!非常感谢!
猜你喜欢
  • 2015-02-26
  • 1970-01-01
  • 2014-03-08
  • 1970-01-01
  • 2020-05-10
  • 2017-07-28
  • 1970-01-01
  • 2017-02-07
  • 1970-01-01
相关资源
最近更新 更多