使用 Oracle SQL 中的 rank() 和子查询从更新日期检索最后余额
Retrieve last balance from update date using rank() and subquery in Oracle SQL
我无法从 table 中检索 balance
信息。数据集如下所示:
| Name | Last Name | Balance | Update Date |
+---------------+---------------+---------+-------------+
| John | Doe | 00 | 2017-01-01 |
| John | Doe | | 2017-01-02 |
| John | Doe | | 2017-01-03 |
| John | Doe | | 2017-01-04 |
| John | Doe | | 2017-01-05 |
| John | Doe | | 2017-01-06 |
任务是用[=17=]得到最近的Balance
,但是如果同一个Balance
几天都一样,那么在那种情况下我们需要先得到Update Date
与此 Balance
,所以在那种情况下,我们需要以下结果:
| Name | Last Name | Balance | Update Date |
+---------------+---------------+---------+-------------+
| John | Doe | | 2017-01-04 |
我尝试使用我的查询:
select
a.name,
a.last_name,
a.balance,
a.update_date
from
(select
name,
last_name,
balance,
update_date,
rank () over (partition by name, last_name order by update_date desc) top
from
customer_balance) a
where
a.top = 1
但显然 returns:
| Name | Last Name | Balance | Update Date |
+---------------+---------------+---------+-------------+
| John | Doe | | 2017-01-06 |
我不确定如何修改它以获得所需的结果。请注意,我的访问权限有限,因此不允许使用临时 table、函数或类似的东西。只是简单的选择,没有什么花哨的。
非常感谢你的帮助。
您可以使用 查找具有相同余额的行组,其中包含最新的 update_date 行(整个数据集顶部的行与最新的余额将是 0) 然后一个分组来选择最早的 update_date,像这样:
WITH customer_balance AS (SELECT 'John' first_name, 'Doe' last_name, 1600 balance, to_date('01/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 12 balance, to_date('02/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 1 balance, to_date('03/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 16 balance, to_date('04/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 16 balance, to_date('05/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 16 balance, to_date('06/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 1600 balance, to_date('01/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 12 balance, to_date('02/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 1 balance, to_date('03/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 16 balance, to_date('04/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 15 balance, to_date('05/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 16 balance, to_date('06/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 16 balance, to_date('07/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 1600 balance, to_date('01/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 12 balance, to_date('02/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 1 balance, to_date('03/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 16 balance, to_date('04/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 16 balance, to_date('05/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 16 balance, to_date('06/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 17 balance, to_date('07/01/2017', 'dd/mm/yyyy') update_date FROM dual)
SELECT first_name,
last_name,
balance,
min(update_date) update_date
FROM (SELECT first_name,
last_name,
balance,
update_date,
row_number() OVER (PARTITION BY first_name, last_name ORDER BY update_date DESC) -- row number across the entire dataset (i.e. for each first_name and last_name)
- row_number() OVER (PARTITION BY first_name, last_name, balance ORDER BY update_date DESC) grp -- row number across each balance in the entire dataset.
FROM customer_balance)
WHERE grp = 0
GROUP BY first_name,
last_name,
balance;
FIRST_NAME LAST_NAME BALANCE UPDATE_DATE
---------- --------- ---------- -----------
John Doe 16 04/01/2017
John Doe2 16 06/01/2017
John Doe3 17 07/01/2017
我提供了 3 个场景:
- 最新的行是相同的余额,但该余额没有在数据集(即您的原始数据集)中出现得更早
- 最新的行是相同的余额,但该余额在数据集中出现得更早
- 最新一行的余额与前一行不同。
也许你可以试试这个查询
WITH bal AS
(SELECT 'John' first_name,
'Doe' last_name,
1600 balance,
to_date('20170101', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
12 balance,
to_date('20170102', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
1 balance,
to_date('20170103', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
16 balance,
to_date('20170104', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
16 balance,
to_date('20170105', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
16 balance,
to_date('20170106', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
328 balance,
to_date('20170107', 'YYYYMMDD') update_date
FROM dual) -- The main query
SELECT *
FROM
(SELECT bal.*,
LAG(balance) OVER(PARTITION BY first_name, last_name
ORDER BY update_date)prev_balance
FROM bal )
WHERE prev_balance IS NULL
OR balance != prev_balance
第一步我们得到之前的余额。
在第二个中,我们删除所有先前余额等于当前余额的行。
顺便说一句,抱歉我用智能手机回答的布局。
我没有时间写出经过测试的解决方案,但是分析函数 lead()
和 lag()
是为此设计的:
select name, last_name, balance, update_date
from (select name,
last_name,
balance,
update_date,
lead(balance) over (partition by first_name, last_name
order by update_date)
as next_balance
where balance = :target_balance
order by update_date
)
where balance <> next_balance
and rownum = 1
我无法从 table 中检索 balance
信息。数据集如下所示:
| Name | Last Name | Balance | Update Date |
+---------------+---------------+---------+-------------+
| John | Doe | 00 | 2017-01-01 |
| John | Doe | | 2017-01-02 |
| John | Doe | | 2017-01-03 |
| John | Doe | | 2017-01-04 |
| John | Doe | | 2017-01-05 |
| John | Doe | | 2017-01-06 |
任务是用[=17=]得到最近的Balance
,但是如果同一个Balance
几天都一样,那么在那种情况下我们需要先得到Update Date
与此 Balance
,所以在那种情况下,我们需要以下结果:
| Name | Last Name | Balance | Update Date |
+---------------+---------------+---------+-------------+
| John | Doe | | 2017-01-04 |
我尝试使用我的查询:
select
a.name,
a.last_name,
a.balance,
a.update_date
from
(select
name,
last_name,
balance,
update_date,
rank () over (partition by name, last_name order by update_date desc) top
from
customer_balance) a
where
a.top = 1
但显然 returns:
| Name | Last Name | Balance | Update Date |
+---------------+---------------+---------+-------------+
| John | Doe | | 2017-01-06 |
我不确定如何修改它以获得所需的结果。请注意,我的访问权限有限,因此不允许使用临时 table、函数或类似的东西。只是简单的选择,没有什么花哨的。
非常感谢你的帮助。
您可以使用
WITH customer_balance AS (SELECT 'John' first_name, 'Doe' last_name, 1600 balance, to_date('01/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 12 balance, to_date('02/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 1 balance, to_date('03/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 16 balance, to_date('04/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 16 balance, to_date('05/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 16 balance, to_date('06/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 1600 balance, to_date('01/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 12 balance, to_date('02/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 1 balance, to_date('03/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 16 balance, to_date('04/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 15 balance, to_date('05/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 16 balance, to_date('06/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 16 balance, to_date('07/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 1600 balance, to_date('01/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 12 balance, to_date('02/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 1 balance, to_date('03/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 16 balance, to_date('04/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 16 balance, to_date('05/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 16 balance, to_date('06/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 17 balance, to_date('07/01/2017', 'dd/mm/yyyy') update_date FROM dual)
SELECT first_name,
last_name,
balance,
min(update_date) update_date
FROM (SELECT first_name,
last_name,
balance,
update_date,
row_number() OVER (PARTITION BY first_name, last_name ORDER BY update_date DESC) -- row number across the entire dataset (i.e. for each first_name and last_name)
- row_number() OVER (PARTITION BY first_name, last_name, balance ORDER BY update_date DESC) grp -- row number across each balance in the entire dataset.
FROM customer_balance)
WHERE grp = 0
GROUP BY first_name,
last_name,
balance;
FIRST_NAME LAST_NAME BALANCE UPDATE_DATE
---------- --------- ---------- -----------
John Doe 16 04/01/2017
John Doe2 16 06/01/2017
John Doe3 17 07/01/2017
我提供了 3 个场景:
- 最新的行是相同的余额,但该余额没有在数据集(即您的原始数据集)中出现得更早
- 最新的行是相同的余额,但该余额在数据集中出现得更早
- 最新一行的余额与前一行不同。
也许你可以试试这个查询
WITH bal AS
(SELECT 'John' first_name,
'Doe' last_name,
1600 balance,
to_date('20170101', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
12 balance,
to_date('20170102', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
1 balance,
to_date('20170103', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
16 balance,
to_date('20170104', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
16 balance,
to_date('20170105', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
16 balance,
to_date('20170106', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
328 balance,
to_date('20170107', 'YYYYMMDD') update_date
FROM dual) -- The main query
SELECT *
FROM
(SELECT bal.*,
LAG(balance) OVER(PARTITION BY first_name, last_name
ORDER BY update_date)prev_balance
FROM bal )
WHERE prev_balance IS NULL
OR balance != prev_balance
第一步我们得到之前的余额。 在第二个中,我们删除所有先前余额等于当前余额的行。 顺便说一句,抱歉我用智能手机回答的布局。
我没有时间写出经过测试的解决方案,但是分析函数 lead()
和 lag()
是为此设计的:
select name, last_name, balance, update_date
from (select name,
last_name,
balance,
update_date,
lead(balance) over (partition by first_name, last_name
order by update_date)
as next_balance
where balance = :target_balance
order by update_date
)
where balance <> next_balance
and rownum = 1