Sql Oracle是否允许在分区上进行求和,但仅当它遵守某些条件时,否则使用滞后?
因此,我的公司有一个应用程序,它具有特定的应用程序内货币。我们记录每一笔交易。 最近,我们发现有一个bug运行了几个星期,允许用户在某个地方消费货币,即使他们没有。当这种情况发生时,用户根本不会被收取费用:例如,用户有400万美元,并购买了价值1000万美元的东西。其余额将保持在4 现在我们需要找出谁滥用了它,他们的可用余额是多少 我想得到BUG_滥用和一厢情愿累积的专栏,反映非法交易和我们的用户在他们的应用内钱包中真正看到的金额,但我没有办法做到这一点 我想知道,如果结果超过0,我是否可以做一些类似于sumestrelas的事情,或者通过用户顺序、日期或类似的事情来获得一厢情愿的累积结果 我们正在使用oracle。非常感谢您的帮助 用户ID 活动日期 数量 方向 RK 中央机存储器 一厢情愿的 臭虫滥用 1. 02/01/2021 13:37:19,009000 -5 0 1. -5 0 1. 1. 08/01/2021 01:55:40,000000 40 1. 2. 35 40 0 1. 10/01/2021 10:45:41,000000 2. 1. 3. 37 42 0 1. 10/01/2021 10:45:58,000000 2. 1. 4. 39 44 0 1. 10/01/2021 13:47:37,456000 -5 0 5. 34 39 0 2. 13/01/2021 20:09:59,000000 2. 1. 1. 2. 2. 0 2. 16/01/2021 15:14:54,000000 -50 0 2. -48 2. 1. 2. 19/01/2021 02:02:59,730000 -5 0 3. -53 2. 1. 2. 23/01/2021 21:14:40,000000 3. 1. 4. -50 5. 0 2. 23/01/2021 21:14:50,000000 -5 0 5. -55 0 0Sql Oracle是否允许在分区上进行求和,但仅当它遵守某些条件时,否则使用滞后?,sql,oracle,Sql,Oracle,因此,我的公司有一个应用程序,它具有特定的应用程序内货币。我们记录每一笔交易。 最近,我们发现有一个bug运行了几个星期,允许用户在某个地方消费货币,即使他们没有。当这种情况发生时,用户根本不会被收取费用:例如,用户有400万美元,并购买了价值1000万美元的东西。其余额将保持在4 现在我们需要找出谁滥用了它,他们的可用余额是多少 我想得到BUG_滥用和一厢情愿累积的专栏,反映非法交易和我们的用户在他们的应用内钱包中真正看到的金额,但我没有办法做到这一点 我想知道,如果结果超过0,我是否可以做一
你可以试试看。这使用递归子查询分解递归WITH子句,因此它只适用于Oracle 11.2及更高版本 我使用您输入的用户ID、事件日期和金额列。我假设所有三列都被限制为非空,两个事件对于同一用户不能有完全相同的时间戳,并且金额对于购买和其他借记费用等为负数,对于存款或其他贷项为正数 输入数据如下所示:
select user_id, event_date, amount
from sample_data
order by user_id, event_date
;
USER_ID EVENT_DATE AMOUNT
------- ----------------------------- ------
1 02/01/2021 13:37:19,009000000 -5
1 08/01/2021 01:55:40,000000000 40
1 10/01/2021 10:45:41,000000000 2
1 10/01/2021 10:45:58,000000000 2
1 10/01/2021 13:47:37,456000000 -5
2 13/01/2021 20:09:59,000000000 2
2 16/01/2021 15:14:54,000000000 -50
2 19/01/2021 02:02:59,730000000 -5
2 23/01/2021 21:14:40,000000000 3
2 23/01/2021 21:14:50,000000000 -5
也许您的输入数据有其他列,如累积金额,我省略了它,因为它在问题或解决方案中不起作用。您显示一个RK列—我假设您将其计算为解决问题的一个步骤;我在下面的解决方案中重新创建了它
下面是使用递归查询recursive with子句可以执行的操作:
with
p (user_id, event_date, amount, rk) as (
select user_id, event_date, amount,
row_number() over (partition by user_id order by event_date)
from sample_data
)
, r (user_id, event_date, amount, rk, bug_flag, balance) as (
select user_id, event_date, amount, rk,
case when amount < 0 then 'bug' end, greatest(amount, 0)
from p
where rk = 1
union all
select p.user_id, p.event_date, p.amount, p.rk,
case when p.amount + r.balance < 0 then 'bug' end,
r.balance + case when r.balance + p.amount >= 0
then p.amount else 0 end
from p join r on p.user_id = r.user_id and p.rk = r.rk + 1
)
select *
from r
order by user_id, event_date
;
为了产生您想要的结果,您可能需要按顺序处理行:为用户处理第一行后,您将计算第二行,然后计算第三行,依此类推 假设列RK已经计算并按顺序为每个用户排序,则可以执行以下操作:
with
n (user_id, event_date, amount, direction, rk, cum, wishful, bug_abuse) as (
select t.*,
greatest(amount, 0),
case when amount < 0 then 1 else 0 end
from t where rk = 1
union all
select
t.user_id, t.event_date, t.amount, t.direction, t.rk, t.cum,
greatest(n.wishful + t.amount, 0),
case when n.wishful + t.amount < 0 then n.wishful
else n.wishful + t.amount
end
from n
join t on t.user_id = n.user_id and t.rk = n.rk + 1
)
select *
from n
order by user_id, rk;
滥用意味着用户做了不该做的事情。你说这是一个bug,所以是由你的公司引起的。所以,不要称之为虐待;你的用户甚至没有利用这个漏洞。他们从中受益;他们也可能没有意识到这一点。毕竟,你是受此影响的人,甚至有几天你都没有注意到。试着理解你的数据,因为你认为自己这样做没有帮助。是负数购买,还是正数存款?方向列只是一个标志吗?0表示购买,1表示存款,因此是无用的信息复制?如果您将购买标记为错误滥用请注意,我反对上面的术语,您是否希望标记该交易,并将用户的钱包余额视为不允许该滥用购买,以便检查剩余交易?很可能这都可以在单个SQL查询中完成,但是你需要一个非常清晰的问题描述,就像我在之前的评论中写的那样,尤其是想要的输出。同样非常重要的是:您的Oracle版本是什么?因为不同版本的数据库引入了不同的高级功能。我同意,BUG_滥用这个词只是一个玩笑,因为它是一厢情愿的累积。有些人肯定滥用了它,不正当地购买了近4k次的东西。事实上,方向栏是我碰巧保存的无用信息的重复。我认为,帮助我更清晰地想象一些不可行的解决方案可能会很有用。我们正在使用oracle 12cHa!完全相同的解决方案。由于懒惰,我认为RK已经计算出来了。@TheImpler-差不多了。在递归分支中,您的解决方案具有greatestn.wiswish+t.amount,0,它似乎与列列表中的任何内容都不对应-相反,缺少bug_滥用的计算。嘿,非常感谢!我使用了您的解决方案,只是保留了rk,因为它确实是按用户划分的行数,按事件顺序,按日期asc。用户ID、事件日期和金额确实不是空的,用户不能有相同的事件日期。谢谢。这个解决方案与@mathguy发布的非常相似,但他的解决方案可以帮助我直接检查
我的交易被窃听了,所以我决定用他的。我真的很感谢你的帮助@如果mathguy的答案是正确的,那么接受它。
with
n (user_id, event_date, amount, direction, rk, cum, wishful, bug_abuse) as (
select t.*,
greatest(amount, 0),
case when amount < 0 then 1 else 0 end
from t where rk = 1
union all
select
t.user_id, t.event_date, t.amount, t.direction, t.rk, t.cum,
greatest(n.wishful + t.amount, 0),
case when n.wishful + t.amount < 0 then n.wishful
else n.wishful + t.amount
end
from n
join t on t.user_id = n.user_id and t.rk = n.rk + 1
)
select *
from n
order by user_id, rk;