【问题标题】:Access SQL return nth row for each given fieldAccess SQL 返回每个给定字段的第 n 行
【发布时间】:2015-04-13 05:26:50
【问题描述】:

我的问题

假设我有一个返回以下数据的查询:

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
...

鉴于 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
...

请注意,日期不是按顺序排列的(您可能在一行和下一行之间有间隔)。

我的问题有直接的 SQL 解决方案吗?(我知道我可以使用 vba 来实现我的目标,但我宁愿继续使用 SQL)

作为澄清说明,请参阅此示例。给定以下结果集:

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

结果应该是:

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

请记住,每个 ID 至少有 120 条记录,这是事实(我有一个查询,只给出超过 119 条记录的 ID)

尝试的解决方案

我尝试使用SELECT TOP 指令,但我无法获得我想要的结果,因为我无法直接应用它:我不想要前 120 名,然后得到我想要的最后一行每个 ID 的 TOP 120 中的最后一个。

为(一秒)澄清而编辑

我的目标是:

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

可惜我不知道如何在access中实现120thRow功能。

【问题讨论】:

  • 记录号是多少?您的问题似乎缺少一些重要的信息。数据中的某列是否为“120”?
  • 不,我在另一个查询中使用 120 条件来获取结果。我尝试(但失败了)解释每个 ID 我有超过 120 条记录(这是事实),我希望每个 ID 都有 120 条记录。我会尝试编辑并使其更清晰
  • 我认为你应该澄清更多。为什么除了id 1还有2015-03-24?它不是第一个,不是最后一个,不是最小值或最大值。为什么会在那里?
  • @LaszloTenki,这是棘手的部分。这不是最后一个,最小或最大。我需要 120 个计数并且我没有自动编号,因为这是一个查询并且自动数字字段已损坏。如果它直接来自任何聚合函数的调用,那么使用 group by 和聚合将非常容易。
  • 再问:你总是需要120,即使你有更多?似乎是这样,但我想确定一下。所以当你有 x 时,当 x 120 时你需要 120?

标签: sql ms-access ms-access-2003


【解决方案1】:

这在 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
               );

编辑:

我猜 MS Access 不允许在关联子句中嵌套。你可以这样做更痛苦:

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;

【讨论】:

  • 对不起,不工作。首先我得到syntax error,因为有对t2.id 的引用,但没有t2 别名。我尝试使用 t1t2t3 作为别名,但内部查询出错,访问请求 t。 id 字段(如果我很好地跟着你,那么 t1.id)。
  • @mTorres 。 . .我不肯定这是否可行。我猜 Access 不允许嵌套关联子句。
【解决方案2】:

对不起我之前的回答,我误解了你。我有另一种方法,但在 SQL 中。我几乎可以肯定它在 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

【讨论】:

  • 对不起,使用聚合函数没有帮助,因为我想要每个 ID 的第 120 条记录,也不是最小值,最大值,每个 ID 的第 120 条。
  • 哦,现在我明白了。对不起,我不清楚。
  • 但是您使用的是索引吗?因为没有它可能无法确定,所以它正在改变第 120 行。
  • 我不能使用索引,因为它不是直接基于一个表,而是来自另一个查询的结果集,这会破坏我的索引。我的结果集来自this answer
  • 我改变了我的答案给你一些想法,但它是 SQL 而不是真正的 Access。
【解决方案3】:

最后,我设法为每一天和 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

从这里开始,只需从此结果集中选择 rownum = 120 的行并结束游戏。

【讨论】:

  • 我知道您最终使用了 count,但您是否设法找到了一个更好的解决方案 - 一个更纯粹的解决方案?多年后的人们很想看到这个答案,这是一个很好的问题............
  • @BKSpureon,不,我仍在内部计算中使用此查询。如果有人有更好的主意,我会全力以赴:-)
【解决方案4】:

您好,我认为这一定对您有用。

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 – 提及对表格进行排序的列的名称。
  • n – 行号
  • table_name – 提表名表名

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-27
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多