如何选择n组的所有记录?

时间:2016-09-19 21:49:54

标签: sql sql-server

我想选择前n个组的记录。我的数据如下:

表'跑步者':

    id    gid    status    rtime
    ---------------------------
    100   5550   1         2016-08-19 
    200   5550   2         2016-08-22
    300   5550   1         2016-08-30
    100   6050   3         2016-09-01
    200   6050   1         2016-09-02
    100   6250   1         2016-09-11
    200   6250   1         2016-09-15
    300   6250   3         2016-09-19

表'静态'

    id    description   env
    -------------------------------
    100   something 1   somewhere 1
    200   something 2   somewhere 2
    300   something 3   somewhere 3

单元ID(id)在组内是唯一的,但在其列中不唯一,因为该组的实例是定期生成的。组ID(gid)分配给每个单元,但不会在多个实例上生成。

现在,组合表并选择所有内容或按特定值过滤很容易,但如何在不直接引用组ID的情况下选择前两组的所有记录? 预期结果将是:

    id    gid    description   status    rtime
    --------------------------------------
    300   6250   something 2   3         2016-09-19
    200   6250   something 1   1         2016-09-15
    100   6250   something 3   1         2016-09-11
    200   6050   something 2   1         2016-09-02
    100   6050   something 1   3         2016-09-01

额外问题:当我过滤这样的时间范围时:

    [...]
    WHERE runner.rtime BETWEEN '2016-08-25' AND '2016-09-16'

是否有一种简单的方法可以确保群组不被切断,但是要么显示所有记录,要么根本不显示?

5 个答案:

答案 0 :(得分:1)

嗯。我怀疑这可能会做你想要的:

select top (1) with ties r.*
from runner r
order by min(rtime) over (partition by gid), gid;

至少,这将获得完整的第一组。

无论如何,我们的想法是将gid作为order by中的关键字并使用top with ties

答案 1 :(得分:1)

您可以使用ROW_NUMBER()执行此操作。首先,创建一个对组进行排名的查询:

SELECT    gid, ROW_NUMBER() over (order by gid desc) as RN
FROM      Runner
GROUP BY  gid

然后将其用作派生表以获取其他信息,并使用where子句过滤到要查看的组数。例如,下面将返回前5个组RN <= 5

SELECT     id, R.gid, description, status, rtime
FROM       (SELECT   gid, ROW_NUMBER() over (order by gid desc) as RN
            FROM     Runner
            GROUP BY gid) G
INNER JOIN Runner R on R.gid = G.gid
INNER JOIN Statis S on S.id = R.id
WHERE      RN <= 5 --Change this to see more or less groups

关于日期的第二个问题,您可以使用如下子查询来执行此操作:

SELECT *
FROM   Runner
WHERE  gid IN (SELECT gid 
               FROM   Runner 
               WHERE  rtime BETWEEN '2016-08-25' AND '2016-09-16')

答案 2 :(得分:1)

您可以执行以下操作

with report as(
select n.id,n.gid,m.description,n.status,n.rtime, dense_rank() over(order by gid desc)  as RowNum
from @table1 n
inner join @table2 m on n.id = m.id )

select id,gid,description,status,rtime
from report
where RowNum<=2 -- <-- here n=2
order by gid desc,rtime desc

这是一个有效的demo

答案 3 :(得分:1)

DENSE_RANK看起来像是一个理想的解决方案

Select * From 
(
select DENSE_RANK() over (order by gid desc) as D_RN, r.*
from runner r
) A
Where D_RN = 1

答案 4 :(得分:0)

无需使用排名功能(ROW_NUMBERDENSE_RANK等)。

SELECT r.id, gid, [description], [status], rtime
FROM runner r
INNER JOIN static s ON r.id = s.id
WHERE gid IN (
    SELECT TOP 2 gid FROM runner GROUP BY gid ORDER BY gid DESC
)
ORDER BY rtime DESC;

同样使用CTE:

WITH grouped
AS
(
    SELECT TOP 2 gid 
    FROM runner GROUP BY gid ORDER BY gid DESC
)
SELECT r.id, grouped.gid, [description], [status], rtime
FROM runner r
INNER JOIN static s ON r.id = s.id
INNER JOIN grouped ON r.gid = grouped.gid
ORDER BY rtime DESC;