如何编写sql查询以选择一列中具有最大值的行
Posted
技术标签:
【中文标题】如何编写sql查询以选择一列中具有最大值的行【英文标题】:how to write sql query to select rows with max value in one column 【发布时间】:2017-06-28 02:53:10 【问题描述】:我的桌子是这样的。
Id | Name | Ref | Date | From
10 | Ant | 100 | 2017-02-02 | David
10 | Ant | 300 | 2016-01-01 | David
2 | Cat | 90 | 2017-09-09 | David
2 | Cat | 500 | 2016-02-03 | David
3 | Bird | 150 | 2017-06-28 | David
这就是我想要的结果。
Id | Name | Ref | Date | From
3 | Bird | 150 | 2017-06-28 | David
2 | Cat | 500 | 2016-02-03 | David
10 | Ant | 300 | 2016-01-01 | David
我的目标是每个 ID 的最高 Ref,按 Order Date desc 排序。
能否请您告诉我如何使用 pl/sql 编写 sql 查询。
【问题讨论】:
每次你被要求解决一个关于“最高”或“最低”的问题时,你必须考虑重复(并列)。如果 Ant 的两行 Ref = 300 会怎样?两者哪个“最高”?您需要在结果中包含两行吗?还是只取最近日期的那个?或者在 Ref 列中不可能重复?然后,当您按日期排序结果时 - 如果两个日期相等,您如何打破平局? 【参考方案1】:这种要求(您需要一列的最大值或最小值,按另一列分组,但您需要最大值或最小值行中的所有数据)几乎就是 分析函数为了。我使用了row_number
- 如果可能有联系,您需要澄清分配(请参阅我在您的问题下的评论),并且根据细节,另一个分析功能可能更合适 - 也许rank()
。
with
my_table ( id, name, ref, dt, frm ) as (
select 10, 'Ant' , 100, date '2017-02-02', 'David' from dual union all
select 10, 'Ant' , 300, date '2016-01-01', 'David' from dual union all
select 2, 'Cat' , 90, date '2017-09-09', 'David' from dual union all
select 2, 'Cat' , 500, date '2016-02-03', 'David' from dual union all
select 3, 'Bird', 150, date '2017-06-28', 'David' from dual
)
-- End of simulated table (for testing purposes only, not part of the solution).
-- SQL query begins BELOW THIS LINE.
select id, name, ref, dt, frm
from (
select id, name, ref, dt, frm,
row_number() over (partition by id order by ref desc, dt desc) as rn
from my_table
)
where rn = 1
order by dt desc
;
ID NAME REF DT FRM
-- ---- --- ---------- -----
3 Bird 150 2017-06-28 David
2 Cat 500 2016-02-03 David
10 Ant 300 2016-01-01 David
【讨论】:
【参考方案2】:你可以用这个
SELECT
Id
,Name
,Ref
,[Date]
FROM(
SELECT
*
, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Ref DESC) AS Row#
FROM yourtable
) A WHERE Row# = 1
ORDER BY A.[Date] DESC
【讨论】:
【参考方案3】:另一种自加入的解决方案(想法来自这里:How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?):
with
my_table ( id, name, ref, dt, frm ) as (
select 10, 'Ant' , 100, date '2017-02-02', 'David' from dual union all
select 10, 'Ant' , 300, date '2016-01-01', 'David' from dual union all
select 10, 'Ant' , 300, date '2015-01-01', 'David' from dual union all
select 2, 'Cat' , 90, date '2017-09-09', 'David' from dual union all
select 2, 'Cat' , 500, date '2016-02-03', 'David' from dual union all
select 3, 'Bird', 150, date '2017-06-28', 'David' from dual
)
-- End of simulated table (for testing purposes only, not part of the solution).
-- SQL query begins BELOW THIS LINE.
select m1.*
from my_table m1
left join my_table m2
on m1.id = m2.id and (
-- this is basically a comparator: order by ref desc, dt desc
m1.ref < m2.ref or (
m1.ref = m2.ref and
m1.dt < m2.dt
)
) where m2.id is null order by m1.dt desc
;
ID NAME REF DT FRM
---------- ---- ---------- --------- -----
3 Bird 150 28-JUN-17 David
2 Cat 500 03-FEB-16 David
10 Ant 300 01-JAN-16 David
【讨论】:
【参考方案4】:使用“优于”SQL 主体:
select a.Id, a.Name, a.Ref, a.Dt, a.frm
from table_name a
left join table_name b on a.id = b.id and b.ref > a.ref -- b.ref > a.ref would make b.ref "better" that a
where b.id is null -- Now check and make sure there is nothing "better"
group by a.id;
【讨论】:
【参考方案5】:SELECT Id, Name, Max(Ref) as Ref, Min(`Date`) as `Date`
From Forge
Group By Id, Name
Order by Min(`Date`) desc;
【讨论】:
这看起来不像 Oracle - Oracle 中没有反引号。修复此问题后,查询将从一行中选择 max(ref) 并从另一行中选择 min(date) - 这不是 OP 想要的。以上是关于如何编写sql查询以选择一列中具有最大值的行的主要内容,如果未能解决你的问题,请参考以下文章