我的数据看起来像这样
id date total amount adj amount
1 2017-01-02 100 50
1 2017-01-02 50 0
2 2017-01-15 100 35
2 2017-01-15 35 0
3 2017-01-30 120 50
3 2017-01-30 -120 -50
3 2017-01-30 100 50
3 2017-01-30 50 0
3 2017-01-30 60 40
输出应该看起来像,我不知道如何在行和列之间进行减法。
id date due amount
1 2017-01-02 0
2 2017-01-15 0
3 2017-01-30 40
这是我当前的代码,但它可能仅适用于1和2,但绝对不适用于3。
这部分的逻辑是为每个id查找每个条目之间的到期金额。例如,id 1有两个条目,总金额为100,然后他支付了50,所以调整金额为50,而第二个条目,总金额为50,他支付了50,te调整金额为0。因此id 1到期最后的数量是0。
id 3有5个条目,首先有条目显示ID 3的总金额是120,他支付了70,所以调整金额是50,但是第一个条目是错误的,因此所有金额都被修改。那么第三个条目显示的总额为100,ID 3支付了50,因此调整金额为50。然后,第四个条目显示的总额为50,ID 3也支付了50,因此调整金额为0。条目显示总金额为60,并且ID 3支付了20,因此调整金额为40。因此,最终ID 3的应付款为40;
select distinct a.id,
a.date,
case when a.date=b.date and a.total_amount = b.adj_amount then a.adj_amount
when a.date=b.date and a.total_amount <> b.adj_amount then ABS(a.adj_amount + b.adj_amount)
else a.adj_amount
end as due_amount
from table a,
table b
where a.id=b.id;
我只是想知道是否有任何函数可以在行和列之间进行这种计算。
答案 0 :(得分:0)
使用GROUP BY
和SUM()
。
SELECT the_date, SUM(due_amount)
FROM tab
GROUP BY the_date;
答案 1 :(得分:0)
如果可以订购交易,类似的事情可能会起作用。请注意,我已经重命名了某些列,以帮助阐明它们的含义。我还添加了trans_seq_num列,以指示特定日期的客户交易顺序。我认为您正在寻找客户自上次付款以来仍欠的金额。
WITH sample (id, trans_seq_num, some_date, starting_balance, ending_balance) AS
(
SELECT '1',1,'2017-01-02','100','50' FROM dual UNION ALL
SELECT '1',2,'2017-01-02','50','0' FROM dual UNION ALL
SELECT '2',1,'2017-01-15','35','0' FROM dual UNION ALL
SELECT '2',2,'2017-01-15','100','35' FROM dual UNION ALL
SELECT '3',1,'2017-01-30','120','50' FROM dual UNION ALL
SELECT '3',2,'2017-01-30','-120','-50' FROM dual UNION ALL
SELECT '3',3,'2017-01-30','100','50' FROM dual UNION ALL
SELECT '3',4,'2017-01-30','50','0' FROM dual UNION ALL
SELECT '3',5,'2017-01-30','60','40' FROM dual
)
SELECT DISTINCT id,
some_date,
LAST_VALUE(ending_balance) OVER (PARTITION BY id ORDER BY trans_seq_num RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) day_balance
FROM sample
ORDER BY 1,2,3;
ID SOME_DATE AMOUNT_DUE
----- --------------- ---------------
1 2017-01-02 0
2 2017-01-15 35
3 2017-01-30 40
答案 2 :(得分:0)
其他人已经说过:您应该以任何方式对行进行编号。简单的顺序即可完成工作。有了这样独特的列解决方案就很简单了,我们只为每个id找到最后一行。
但是您没有命令。这是我的尝试,到目前为止看起来还不错,可能会提供临时帮助:
with q as (
select table_a.*,
row_number() over (partition by id, date_, total_amount, adj_amount
order by null) rn
from table_a),
t as (
select a.*,
row_number() over (partition by id, date_, total_amount
order by null) r1,
row_number() over (partition by id, date_, adj_amount
order by null) r2
from q a
where not exists (
select 1 from q b
where a.id = b.id and a.date_ = b.date_ and a.rn = b.rn
and a.total_amount = -b.total_amount and a.adj_amount = -b.adj_amount))
select id, date_, max(adj_amount) due
from t
where connect_by_isleaf = 1
connect by prior id = id and prior date_ = date_
and prior adj_amount = total_amount and prior r2 = r1
group by id, date_;
首先,我消除了错误。子查询t
是这样做的,它很简单不存在并添加了row_number
以正确处理多种情况(例如(120,50)=>(-120,-50)和再次(120,50))。
数据已清除,因此我们可以通过先前的adj_amount = total_amount递归地找到连接的行。我们必须再次使用row_numbers来处理相同的行(60,40)=>(40,0)=>(60,40)。
然后仅提取叶子,最后获取这些叶子的最大值,如果每个id存在,则它们应包含孤立的非零值。您可以添加connect_by_path()
子句以查看连接是否正常工作。
分层查询的速度比其他查询慢,因此如果表很大,请警告。如果需要,首先过滤数据。
此查询适用于您的示例以及我想象和测试的其他示例。但是,即使可行,您也应该添加排序列(如果可能的话),并且可以通过有保证的简单方法来获得正确的结果。