SQL通过两个唯一列选择最近日期的行

115

使用以下查询和结果,我正在寻找ChargeId和ChargeType是唯一的最新条目。

select chargeId, chargeType, serviceMonth from invoice

    CHARGEID    CHARGETYPE  SERVICEMONTH
1   101         R           8/1/2008
2   161         N           2/1/2008
3   101         R           2/1/2008
4   101         R           3/1/2008
5   101         R           4/1/2008
6   101         R           5/1/2008
7   101         R           6/1/2008
8   101         R           7/1/2008

期望达成的目标:

    CHARGEID    CHARGETYPE  SERVICEMONTH
1   101         R           8/1/2008
2   161         N           2/1/2008
6个回答

161

您可以使用 GROUP BY 按类型和ID对项目进行分组。然后,您可以使用 MAX() 聚合函数来获取最近的服务月份。下面返回一个结果集,其中包括 ChargeId、ChargeType 和 MostRecentServiceMonth。

SELECT
  CHARGEID,
  CHARGETYPE,
  MAX(SERVICEMONTH) AS "MostRecentServiceMonth"
FROM INVOICE
GROUP BY CHARGEID, CHARGETYPE

1
别忘了给MAX(serviceMonth)字段取别名,以防下游需要使用它。 - Ben Hoffstein
2
好的,如果表格中有一行数据:101 N 1/1/2008会发生什么? - tvanfosson
3
根据他的要求,您将会得到额外返回的一行。这是期望的结果。 - Carlton Jenke
1
在帖子中添加了查询别名。tvanfosson - 这将是一个条件,添加到结果集中,这是正确的。 - Mitchel Sellers
2
如果我想同时获取记录ID,我该怎么做? - Donny V.
显示剩余2条评论

65

所以这不是请求者要求的内容,但它是“SQL通过最近日期选择行”的答案。

修改自http://wiki.lessthandot.com/index.php/Returning_The_Maximum_Value_For_A_Row

SELECT t.chargeId, t.chargeType, t.serviceMonth FROM( 
    SELECT chargeId,MAX(serviceMonth) AS serviceMonth
    FROM invoice
    GROUP BY chargeId) x 
    JOIN invoice t ON x.chargeId =t.chargeId
    AND x.serviceMonth = t.serviceMonth

2
谢谢!这就是我在寻找的! - Diana
似乎与视图不兼容。 - marknuzz

12

我发现大多数开发人员在使用内联查询时,并没有考虑到其对大量数据的影响。

简单来说,你可以通过以下方式实现:

select a.chargeId, a.chargeType, a.serviceMonth 
from invoice a
left outer join invoice b
on a.chargeId=b.chargeId and a.serviceMonth <b.serviceMonth 
where b.chargeId is null
order by a.serviceMonth desc

11
SELECT chargeId, chargeType, MAX(serviceMonth) AS serviceMonth 
FROM invoice
GROUP BY chargeId, chargeType

1
select to.chargeid,t0.po,i.chargetype from invoice i
inner join
(select chargeid,max(servicemonth)po from invoice 
group by chargeid)t0
on i.chargeid=t0.chargeid

以上查询将在不同的收费类型组合具有不同的唯一收费ID时起作用。希望这个简单的查询能够帮助考虑到较少的性能时间...

1

sqlfiddle上查看演示:

  1. 传统方式。
select 
    chargeid, 
    chargetype,
    SERVICEMONTH
from invoice t0
where t0.SERVICEMONTH = (
    select max(SERVICEMONTH) 
    from invoice t1 
    where t1.chargeid = t0.chargeid
    and t1.chargetype = t0.chargetype
);

使用窗口函数。
with w_o as (
    select
        chargeid, 
        chargetype,
        SERVICEMONTH,
        row_number() OVER (PARTITION BY chargeid, chargetype ORDER BY SERVICEMONTH DESC) rn
    from invoice
)
select
    chargeid, 
    chargetype,
    SERVICEMONTH
from w_o
where rn = 1;

了解并能够使用两种风格是很好的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接