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

How to filter out the first and last entry from a table using 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

我想过滤掉 firstlast 值(当 table 在 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 专家,所以我的问题是如果 table 有大约 800000 行并且任何列上都没有索引,那么哪个性能最快。

您可以使用 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))

这里有一个与 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 ) 

你可以用 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