【问题标题】:How can I group on the SAME table, order by date and limit the number of rows returned?如何在 SAME 表上分组、按日期排序并限制返回的行数?
【发布时间】:2016-04-14 15:14:22
【问题描述】:

我想返回一个按 ID_F 分组、在 ID_F 内限制计数并在 ID_F 内按日期排序的集合

这是我的数据库设置:

CREATE TABLE [dbo].[U](
    [ID] [uniqueidentifier] NOT NULL,
    [Name] [nvarchar](max) NULL,
 CONSTRAINT [PK_U] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[F](
    [ID] [uniqueidentifier] NOT NULL,
    [Name] [nvarchar](max) NOT NULL,
 CONSTRAINT [PK_F] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

CREATE TABLE [dbo].[E](
    [ID] [uniqueidentifier] NOT NULL,
    [Name] [nvarchar](max) NOT NULL,
 CONSTRAINT [PK_E] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

CREATE TABLE [dbo].[U_F_E](
    [ID] [uniqueidentifier] NOT NULL,
    [ID_U] [uniqueidentifier] NOT NULL,
    [ID_F] [uniqueidentifier] NOT NULL,
    [ID_E] [uniqueidentifier] NOT NULL,
    [LastUsed][DateTime] NOT NULL,
 CONSTRAINT [PK_U_F_E] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]


declare @ID uniqueidentifier
declare @N nvarchar(50)

set @ID = '53159BEC-88C7-48C3-B2D1-63926ED28A64'
set @N = 'Bob'

insert into [U]
Values(
    @ID,
    @N
    )

set @ID = '3DF035A6-C456-4AB4-8BBB-E8FF86A2A033'
set @N = 'Tom'

insert into [U]
Values(
    @ID,
    @N
    )

set @ID = 'F20AD0BC-3F20-4F1C-A9B8-81AC08EA679A'
set @N = 'F1'

insert into [F]
Values(
    @ID,
    @N
    )

set @ID = '220AD0BC-3F20-4F1C-A9B8-81AC08EA679A'
set @N = 'f2'

insert into [F]
Values(
    @ID,
    @N
    )

set @ID = '3708E1E8-6E7E-4E8F-B415-3F09CF22CB54'
set @N = 'f3'

insert into [F]
Values(
    @ID,
    @N
    )


set @ID = 'EA219DA4-6C13-42AA-A1B6-DE786724A554'
set @N = 'e1'

insert into [E]
Values(
    @ID,
    @N
    )

set @ID = '6158853D-E91A-4AA4-AC0F-5D26F766C677'
set @N = 'e2'

insert into [E]
Values(
    @ID,
    @N
    )

set @ID = 'F697F78A-6990-443E-9D4B-D9BCF046DAF5'
set @N = 'e3'

insert into [E]
Values(
    @ID,
    @N
    )

set @ID = 'A7DB1FA5-28D6-4F5A-8BA0-628EA2A630A8'
set @N = 'e4'

insert into [E]
Values(
    @ID,
    @N
    )

set @ID = '8ABEE9FA-B255-4409-A2DD-30CFF62EEE3C'
set @N = 'e5'

insert into [E]
Values(
    @ID,
    @N
    )

set @ID = 'DA644D24-AFA5-467E-A76C-A5E94DA4FA62'
set @N = 'e6'

insert into [E]
Values(
    @ID,
    @N
    )


insert into [U_F_E]
Values(
    NEWID(),
    '53159BEC-88C7-48C3-B2D1-63926ED28A64', -- bob
    'F20AD0BC-3F20-4F1C-A9B8-81AC08EA679A', -- f1
    'EA219DA4-6C13-42AA-A1B6-DE786724A554', -- e1
    GetDate()
    )

WAITFOR DELAY '00:00:01';
insert into [U_F_E]
Values(
    NEWID(),
    '53159BEC-88C7-48C3-B2D1-63926ED28A64', -- bob
    '3708E1E8-6E7E-4E8F-B415-3F09CF22CB54', -- f3
    'EA219DA4-6C13-42AA-A1B6-DE786724A554', -- e1
    GetDate()
    )

WAITFOR DELAY '00:00:01';
insert into [U_F_E]
Values(
    NEWID(),
    '3DF035A6-C456-4AB4-8BBB-E8FF86A2A033', -- tom
    '220AD0BC-3F20-4F1C-A9B8-81AC08EA679A', -- f2
    '8ABEE9FA-B255-4409-A2DD-30CFF62EEE3C', -- e5
    GetDate()
    )


WAITFOR DELAY '00:00:01';
insert into [U_F_E]
Values(
    NEWID(),
    '53159BEC-88C7-48C3-B2D1-63926ED28A64', -- bob
    '220AD0BC-3F20-4F1C-A9B8-81AC08EA679A', -- f2
    '8ABEE9FA-B255-4409-A2DD-30CFF62EEE3C', -- e5
    GetDate()
    )

WAITFOR DELAY '00:00:01';
insert into [U_F_E]
Values(
    NEWID(),
    '53159BEC-88C7-48C3-B2D1-63926ED28A64', -- bob
    '220AD0BC-3F20-4F1C-A9B8-81AC08EA679A', -- f2
    'F697F78A-6990-443E-9D4B-D9BCF046DAF5', -- e3
    GetDate()
    )

WAITFOR DELAY '00:00:01';
insert into [U_F_E]
Values(
    NEWID(),
    '53159BEC-88C7-48C3-B2D1-63926ED28A64', -- bob
    '220AD0BC-3F20-4F1C-A9B8-81AC08EA679A', -- f2
    '6158853D-E91A-4AA4-AC0F-5D26F766C677', -- e2
    GetDate()
    )

WAITFOR DELAY '00:00:01';
insert into [U_F_E]
Values(
    NEWID(),
    '3DF035A6-C456-4AB4-8BBB-E8FF86A2A033', -- tom
    '220AD0BC-3F20-4F1C-A9B8-81AC08EA679A', -- f2
    'EA219DA4-6C13-42AA-A1B6-DE786724A554', -- e1
    GetDate()
    )

WAITFOR DELAY '00:00:01';
insert into [U_F_E]
Values(
    NEWID(),
    '53159BEC-88C7-48C3-B2D1-63926ED28A64', -- bob
    '220AD0BC-3F20-4F1C-A9B8-81AC08EA679A', -- f2
    'A7DB1FA5-28D6-4F5A-8BA0-628EA2A630A8', -- e4
    GetDate()
    )

尝试 0:

declare @limit int
set @limit = 3

declare @myuser uniqueidentifier
set @myuser = '53159BEC-88C7-48C3-B2D1-63926ED28A64'

select ID_F, e.Name, LastUsed from [U_F_E] as ufe
join E as e on ufe.ID_E = e.ID
where ID_U = @myuser
group by ID_F, e.Name, LastUsed
order by LastUsed desc

这是输出,注意它是按日期分组和排序的……但它不限制返回的 ID_F 行数

ID_F                                    Name    LastUsed
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 07:58:54.953
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 07:51:49.560
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e2  2016-04-14 07:51:47.537
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e5  2016-04-14 07:51:45.533
3708E1E8-6E7E-4E8F-B415-3F09CF22CB54    e1  2016-04-14 07:51:43.530
F20AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e1  2016-04-14 07:51:42.530

当我尝试使用此限制返回的行数时:

declare @limit int
set @limit = 3

declare @myuser uniqueidentifier
set @myuser = '53159BEC-88C7-48C3-B2D1-63926ED28A64'

select TOP(@limit) ID_F, e.Name, LastUsed from [U_F_E] as ufe
join E as e on ufe.ID_E = e.ID
where ID_U = @myuser
group by ID_F, e.Name, LastUsed
order by LastUsed desc

我明白了:

ID_F                                    Name    LastUsed
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 07:58:54.953
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 07:51:49.560
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e2  2016-04-14 07:51:47.537

当我真的想要这个时:

ID_F    Name    LastUsed
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 07:58:54.953
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 07:51:49.560
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e2  2016-04-14 07:51:47.537

3708E1E8-6E7E-4E8F-B415-3F09CF22CB54    e1  2016-04-14 07:51:43.530
F20AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e1  2016-04-14 07:51:42.530

你能帮帮我吗?

尝试 1:

select id_f,name,lastused 
from (
select ID_F, e.Name, LastUsed
,dense_rank() over(partition by ID_U order by ID_F) as rnk
from [U_F_E] as ufe
join E as e on ufe.ID_E = e.ID
where ID_U = @myuser) t
where rnk <= 3
order by lastused desc

返回,但不考虑限制返回的行数:

id_f                                    name    lastused
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 07:58:54.953
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 07:51:49.560
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e2  2016-04-14 07:51:47.537
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e5  2016-04-14 07:51:45.533
3708E1E8-6E7E-4E8F-B415-3F09CF22CB54    e1  2016-04-14 07:51:43.530
F20AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e1  2016-04-14 07:51:42.530

我假设“3”应该限制这样返回的 ID_F 行?

id_f                                    name    lastused
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 07:58:54.953
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 07:51:49.560
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e2  2016-04-14 07:51:47.537

3708E1E8-6E7E-4E8F-B415-3F09CF22CB54    e1  2016-04-14 07:51:43.530
F20AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e1  2016-04-14 07:51:42.530

尝试 2:

SELECT  id_f, fe.*
FROM    [U_F_E] uf
CROSS APPLY
        (
        SELECT  TOP (@limit) e.Name, LastUsed
        FROM    [U_F_E] fe
        JOIN    [E] e
        ON      e.id = fe.id_e
        WHERE   id_f = uf.id_f
        ORDER BY LastUsed DESC
        ) fe
WHERE   id_u = @myuser

但这太离谱了……它会返回疯狂的行数。

id_f                                   Name LastUsed
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 07:58:54.953
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e5  2016-04-14 07:55:38.870
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 07:51:49.560
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 07:58:54.953
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e5  2016-04-14 07:55:38.870
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 07:51:49.560
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 07:58:54.953
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e5  2016-04-14 07:55:38.870
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 07:51:49.560
F20AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e1  2016-04-14 07:51:42.530
3708E1E8-6E7E-4E8F-B415-3F09CF22CB54    e1  2016-04-14 07:51:43.530
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 07:58:54.953
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e5  2016-04-14 07:55:38.870
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 07:51:49.560

尝试 3:

select id_f,name,lastused 
from (
select ID_F, e.Name, LastUsed
,row_number() over(partition by ID_F order by lastused desc) as rnk
from [U_F_E] as ufe
join E as e on ufe.ID_E = e.ID
where ID_U = @myuser) t
where rnk <= @limit
order by lastused desc

给出这个:

id_f                                    name    lastused
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 07:58:54.953
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 07:51:49.560
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e2  2016-04-14 07:51:47.537
3708E1E8-6E7E-4E8F-B415-3F09CF22CB54    e1  2016-04-14 07:51:43.530
F20AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e1  2016-04-14 07:51:42.530

但是当我在表格中添加另一行时,请注意 370 未分组

id_f                                    name    lastused
3708E1E8-6E7E-4E8F-B415-3F09CF22CB54    e5  2016-04-14 08:53:21.233
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 08:50:03.187
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e5  2016-04-14 08:45:00.897
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 08:43:42.253
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e2  2016-04-14 07:51:47.537
3708E1E8-6E7E-4E8F-B415-3F09CF22CB54    e1  2016-04-14 07:51:43.530
F20AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e1  2016-04-14 07:51:42.530

尝试 4:

select id_f,name,lastused 
from (
select ID_F, e.Name, LastUsed
,row_number() over(partition by ID_F order by lastused desc) as rnk
from [U_F_E] as ufe
join E as e on ufe.ID_E = e.ID
where ID_U = @myuser) t
where rnk <= @limit
order by ID_F, lastused desc

产生:(当限制设置为 3 时)

id_f                                   name lastused
3708E1E8-6E7E-4E8F-B415-3F09CF22CB54    e5  2016-04-14 08:53:21.233
3708E1E8-6E7E-4E8F-B415-3F09CF22CB54    e1  2016-04-14 07:51:43.530
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 08:50:03.187
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e5  2016-04-14 08:45:00.897
220AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e3  2016-04-14 08:43:42.253
F20AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e4  2016-04-14 09:00:27.780
F20AD0BC-3F20-4F1C-A9B8-81AC08EA679A    e1  2016-04-14 07:51:42.530

谢谢你!

【问题讨论】:

  • 这是 SQL Server 吗?哪个版本?
  • 那么您想要每个用户的top 3 行吗?还是最近三个用户的行?
  • 我想将 ID_F 组限制为 N 行
  • 所以它是#2?但是为什么不包括220AD0BC-3F20-4F1C-A9B8-81AC08EA679A e5 2016-04-14 07:51:45.533
  • dnoeth - 我想知道每个 ID_F 分组中前 N 个 ID_F 行的最后使用日期

标签: sql-server sql-server-2012 group-by sql-order-by


【解决方案1】:

经过chat的讨论,原来主要是显示问题:

select id_f,name,lastused 
from 
 ( 
   select ID_F, e.Name, LastUsed 
      ,row_number()                   -- ranking 
       over(partition by ID_F         -- for each ID_F
       order by lastused desc) as rnk -- based on descending dates
   from [U_F_E] as ufe 
   join E as e on ufe.ID_E = e.ID 
   where ID_U = @myuser
 ) t 
where rnk <= @limit 
order by ID_F, lastused desc -- sort the correct way :-)

【讨论】:

  • 不要忘记 'row_number' 而不是 'dense_rank'
  • @user3174075:除非同一用户有多行具有完全相同的lastused,否则RANKDENSE_RANKROW_NUMBER 之间没有区别。
【解决方案2】:

您可以使用dense_rank函数并检查。

select id_f,name,lastused 
from (
select ID_F, e.Name, LastUsed
,dense_rank() over(partition by ID_U order by ID_F) as rnk
from [U_F_E] as ufe
join E as e on ufe.ID_E = e.ID
where ID_U = @myuser) t
where rnk <= 3
order by lastused desc

【讨论】:

  • order by LastUsed desc 逻辑在哪里?
  • 我只是在最后添加了它。
  • 但是TOP是基于它的。
  • 返回N个ID_F分组的'@limit'在哪里?
  • 试试row_number() over(partition by ID_F order by lastused desc),这可能是OP想要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-16
  • 2011-02-19
  • 1970-01-01
相关资源
最近更新 更多