SQL选择15个最近的行,但每个用户不超过3个

时间:2016-12-05 22:25:19

标签: sql sql-server subset rows criteria

假设我有下表:

public void copy() {
Pixel selectedB= model.getSelected();
if (selectedB != null) {
//    throw new IllegalArgumentException("cannot be null");  //line 81

  PaintBrushToolUI pbtUI = (PaintBrushToolUI)paint_brush_tool.getUI();
  pbtUI.changeView(selectedB);
}

这个测试数据:

CREATE TABLE test_UserAds
(
    UserId int,
    Title varchar(255),
    ActivateDate DATETIME2
);

我希望能够返回ActivateDate(desc)排序的前15行,但每个用户不超过3行。有谁能提出建议?

预期的结果集如下所示:

INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 1, 'Waiter', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 1, 'Policeman', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 1, 'Data Clerk', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 1, 'Nurse', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 2, 'Chef', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 2, 'Teacher', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 2, 'Mechanic', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 2, 'Cleaner', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 2, 'Painter', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 2, 'Bricklayer', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 2, 'Plasterer', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 2, 'Electrician', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 3, 'Programmer', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 3, 'Driver', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 3, 'Photographer', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 3, 'Carpenter', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 3, 'CEO of some nasty Corporation', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 3, 'Writer', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 3, 'Labourer', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 3, 'Stack Overflow Bore', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 4, 'Surgeon', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 4, 'Diver', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 4, 'Chicken sexer', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 4, 'Bottle washer', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 4, 'Food Tester', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 4, 'Chemist', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 4, 'Biologist', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 4, 'Secretary', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 5, 'Doctor', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 5, 'Developer', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 5, 'Designer', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 5, 'Tramp', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 5, 'Clock watcher', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 5, 'Pedant', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 5, 'Neuromancer', SYSDATETIME())
INSERT INTO dbo.test_UserAds ( UserId, Title, ActivateDate ) VALUES  ( 5, 'Gardener', SYSDATETIME())

1 个答案:

答案 0 :(得分:1)

在SQL Server中,您可以使用row_Number()为每个用户获取最新的三个。然后只需要最新的15个:

select top 15 ua.*
from (select ua.*,
             row_number() over (partition by userid order by activatedate desc) as seqnum
      from dbo.test_UserAds ua
     ) ua
where seqnum <= 3  -- get three most recent for each user
order by activatedate desc;

如果你有一个用户表,你也可以这样做:

select top 15 ua.*
from users u cross apply
     (select top 3 ua.*
      from dbo.test_UserAds ua
      where ua.userid = u.userid
      order by activatedate desc
     ) ua
order by activatedate desc;