简体   繁体   English

访问SQL返回每个给定字段的第n行

[英]Access SQL return nth row for each given field

My problem 我的问题

Let's say I have a query that returns the following data: 假设我有一个返回以下数据的查询:

id     date
--    ------
1     2015-01-12
1     ... // here I might have X more rows
1     2015-06-30
2     2015-01-12
2     ... // here I might have Y more rows
2     2015-05-20
...

Given that X, Y >= 120 and X != Y and the order of the query is id, date ASC I want a way to retrieve the record number 120 for id 1 and the 120 for the id 2 (and so on for each different ID), something like: 给定X, Y >= 120 and X != Y并且查询的顺序是id, date ASC我想要一种方法来检索id为1的记录号120和id为2的记录号120(依次类推)不同的ID),例如:

id      date
--    --------
1     2015-03-24 // this is the record 120 for id = 1
2     2015-04-26 // this is the record 120 for id = 2
...

Notice that the dates don't follow a sequential order (you may have a gap between one row and the next one). 请注意,日期不是按照顺序排列的(一行和下一行之间可能会有间隔)。

Is there a direct SQL solution for my problem? 我的问题是否有直接的SQL解决方案? (I know I can use vba to achieve my goal but I rather stay with SQL) (我知道我可以使用vba来实现我的目标,但我宁愿使用SQL)

As a clarification note, see this example. 作为说明,请参见此示例。 Given the following resultset: 给定以下结果集:

id     date
--    ------
1     2015-01-12  // this is record 1 for id = 1
1     2015-01-13  // this is record 2 for id = 1
1     2015-01-20  // this is record 3 for id = 1
1     2015-01-21  // this is record 4 for id = 1
...
1     2015-03-22  // this is record 118 for id = 1
1     2015-03-23  // this is record 119 for id = 1
1     2015-03-24  // this is record 120 for id = 1
1     2015-03-25  // this is record 121 for id = 1
...
1     2015-06-30  // this is the last row for id = 1
2     2015-01-12  // this is record 1 for id = 2
2     2015-01-13  // this is record 2 for id = 2
...
2     2015-04-25  // this is record 120 for id = 2
...
2     2015-05-20  // this is the last record for id = 2

The result should be: 结果应为:

id      date
--    --------
1     2015-03-24
2     2015-04-26

Remember, I have at least 120 records for each ID, this is a fact (I have a query that gives only the IDs with more than 119 records) 请记住,我每个ID至少有120条记录,这是事实(我有一个查询,仅给出具有119条以上记录的ID)

Attempted solution 尝试的解决方案

I've tried to play with the SELECT TOP directive, but I fail to achieve the results I want as I cannot apply it direcly: I don't want the top 120 and then get the last row as I want the last one of the TOP 120 for each ID. 我尝试使用SELECT TOP指令,但是由于无法直接应用它而无法达到我想要的结果:我不希望前120个,然后获得最后一行,因为我想要最后一个每个ID的前120名。

Edited for (a second) clarification 编辑(第二次)澄清

My goal would be to have something like: 我的目标是拥有这样的东西:

SELECT id, 120thRow(date)
FROM table
GROUP BY id;

unfortunatelly I don't know how to implement the 120thRow function in access. 不幸的是,我不知道如何在访问中实现120thRow函数。

Does this work in Access? 这在Access中有效吗?

select t.*
from table as t
where t.date = (select top 1 date
                from (select top 120 date
                      from table t2
                      where t2.id = t.id
                      order by date
                     ) as tt
                order by date desc
               );

EDIT: 编辑:

I guess MS Access doesn't allow nesting in the correlation clause. 我想MS Access不允许在相关子句中嵌套。 You can do this more painfully as: 您可以通过以下方式更痛苦地完成此操作:

select t.*
from table as t join
     (select t.id, max(t.date) as maxdate
      from table as t
      where t.date = (select top 120 date
                      from table as t2
                      where t2.id = t.id
                      order by date
                     )
     ) tt
     on t.id = tt.id and t.date = tt.maxdate;

Sorry for my previous answer, I misunderstood you. 对不起,我以前的回答,我误会了你。 I have another approach but in SQL. 我有另一种方法,但在SQL中。 I am almost sure that it does not work in Access but might give you an idea. 我几乎可以肯定它在Access中不起作用,但可能会给您一个想法。

-- start: this is just preparation of some sample data
declare @t table (id int, date datetime)
declare @id int, @d datetime, @c int
set @c = 0
set @id = 1
set @d = '2015-01-01'
while @c <= 125
    begin
    insert into @t values (@id, @d)
    set @d = dateadd(day, 1, @d)
    set @c = @c + 1
    end
set @c = 0
set @id = 2
set @d = '2015-01-02'
while @c <= 125
    begin
    insert into @t values (@id, @d)
    set @d = dateadd(day, 1, @d)
    set @c = @c + 1
    end
-- end: this is just preparation of some sample data

-- this is somewhat like what you need:
select id, date from 
(select id, date, row_number() over (partition by id order by date) as rc from @t) as mytable
where rc = 120

In the end, I've managed a way to put a row counter for each day and ID like so: 最后,我设法了一种为每天和ID放置一个行计数器的方法,如下所示:

select id, date, 
       (
          select count(date) 
          from table As t1 
          where t1.id = t.id
            and t1.date <= t.date
       ) As rowNum
from table As t

From here on it's just a matter of selecting from this resultset the rows which has rownum = 120 and game over. 从这里开始,只需从该结果集中选择rownum = 120并结束游戏的行即可。

Hi I think this must work for you. 嗨,我认为这必须为您工作。

with Records AS
(select row_number() over(order by sort_column_name) as 'row', * 
       from table_name) select * from records where row=n
  • sort_column_name – mention the name of the column which is sorting the table. sort_column_name –提及对表进行排序的列的名称。
  • n – row number n –行号
  • table_name – mention the name of the table table name table_name –提及表的名称表名

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM