如何使用RANK过滤掉表中的第一个和最后一个条目?

时间:2015-03-04 15:37:06

标签: sql group-by rank

我有这些数据:

Id   Date  Value
'a'  2000  55
'a'  2001  3
'a'  2012  2
'a'  2014  5
'b'  1999  10
'b'  2014  110
'b'  2015  8
'c'  2011  4
'c'  2012  33

我想过滤掉第一个 last 值(当表在Date列上排序时),并且只保留其他值。如果只有两个条目,则不返回任何内容。 (Id =' c'的例子)

ID   Date  Value
'a'  2001  3
'a'  2012  2
'b'  2014  110 

我尝试使用order by(RANK()OVER(PARTITION BY [Id] ORDER BY Date ...))结合本文(http://blog.sqlauthority.com/2008/03/02/sql-server-how-to-retrieve-top-and-bottom-rows-together-using-t-sql/),但我无法得到它工作


[更新]
所有3个答案似乎都很好。但我不是SQL专家,所以我的问题是如果表有大约800000行并且任何列都没有索引,哪一个具有最快的性能。

3 个答案:

答案 0 :(得分:1)

您可以使用row_number两次来确定minmax日期,然后相应地进行过滤:

with cte as (
  select id, [date], value, 
    row_number() over (partition by id order by [date]) minrn,
    row_number() over (partition by id order by [date] desc) maxrn
  from data
  )
select id, [date], value
from cte
where minrn != 1 and maxrn != 1

这是使用minmax的另一种方法,无需使用排名功能:

with cte as (
  select id, min([date]) mindate, max([date]) maxdate
  from data
  group by id 
  )
select * 
from data d
where not exists (
    select 1
    from cte c
    where d.id = c.id and d.[date] in (c.mindate, c.maxdate))

答案 1 :(得分:1)

以下是与row_numbercount

类似的解决方案
SELECT id,
       dat,
       value
FROM   (SELECT *,
               ROW_NUMBER()
                 OVER(
                   partition BY id
                   ORDER BY dat)    rnk,
               COUNT(*)
                 OVER (
                   partition BY id) cnt
        FROM   @table) t
WHERE  rnk NOT IN( 1, cnt ) 

答案 2 :(得分:0)

您可以使用EXISTS

执行此操作
SELECT *
FROM Table1 a
WHERE EXISTS (SELECT 1
                  FROM Table1 b
                  WHERE a.ID = b.ID
                   AND b.Date < a.Date
                  )
  AND EXISTS (SELECT 1
                  FROM Table1 b
                  WHERE a.ID = b.ID
                   AND b.Date > a.Date
                  )

演示:SQL Fiddle