使用Microsoft Access查询结果中的行号

15

我经常在SQL Server中使用这个查询来获取表中的行号:

SELECT *
FROM   (SELECT *,
               Row_number()
                 OVER(
                   ORDER BY [myidentitycolumn]) RowID
        FROM   mytable) sub
WHERE  rowid = 15  

我现在正在使用Access 2010,但好像它不起作用了。有没有替代方法可以在Access中实现这个查询?

8个回答

14

在查询中分配行号的另一种方式是使用 DCount 函数。

SELECT *, DCount("[ID]","[mytable]","[ID]<=" & [ID]) AS row_id
FROM [mytable]
WHERE row_id=15

2
这个解决方案很简单,但似乎非常低效。我不会在大型数据集上尝试! - iDevlop

11

MS-Access不支持ROW_NUMBER()函数,可以使用TOP 1代替:

SELECT TOP 1 *
FROM [MyTable]
ORDER BY [MyIdentityCOlumn]

如果你需要获取第15行 - MS-Access没有简单的内置方法来实现。你可以通过使用反向嵌套排序来模拟行号,从而达到这个目的:

SELECT TOP 1 *
FROM (
  SELECT TOP 15 *
  FROM [MyTable]
  ORDER BY [MyIdentityColumn] ) t
ORDER BY [MyIdentityColumn] DESC

5
我知道我会因此被投票否决,但严肃地说,像Access这样一个长期流行的应用程序中,基本问题不应该需要这种解决方法。请注意,我已经尽力让翻译保持忠实,并使其更加通俗易懂,但并未改变原意。 - Damien Golding
1
@DamienGolding,你可以尝试使用DCount更加“直接”的方法,但正如评论所说,这种方法效率不高...而且Access虽然很受欢迎,但更多的是桌面工具,不像真正的服务器解决方案那样功能齐全。 - PinnyM
@PinnyM,您描述的获取第15个数字的方法是否也适用于日期?谢谢。 - JM1
@JM1 当然可以,任何通过 ORDER BY 进行排序的内容都可以使用,包括日期。 - PinnyM
这只是一个发泄情绪的好机会 - 所以随意忽略。TOP x 只是 rownum 的一个目的。因此,提供一个解决单个问题的答案,使其变得不太有用 :P - redevill

4
尽管这是一个老问题,但对我来说这个方法有效,但我从未测试过其效率...
SELECT 
    (SELECT COUNT(t1.SourceID) 
     FROM [SourceTable] t1 
     WHERE t1.SourceID<t2.SourceID) AS RowID, 
    t2.field2, 
    t2.field3, 
    t2.field4, 
    t2.field5
FROM 
    SourceTable AS t2
ORDER BY 
    t2.SourceID;

这种方法的一些优点:

  • 它不依赖于表的顺序 - RowID 是根据其实际值以及小于它的值计算出来的。
  • 此方法可应用于任何(主键)类型(例如NumberStringDate)。
  • 此方法在SQL方面相当独立,或者需要很少的适应性。

明显的缺点

虽然这将适用于几乎任何数据类型,但我必须强调,对于某些数据类型,它可能会创建其他问题。例如,对于字符串,请考虑:

ID 描述 ROWID
aaa 大犀牛 1
bbb 2
ccc 金丝雀 3

如果我插入:bba 野猪,那么金丝雀RowID将会改变...

ID 描述 ROWID
aaa 大犀牛 1
bbb 2
bba 野猪 3
ccc 金丝雀 4

除非表保持未排序状态,否则不能依赖于ID保持不变。


@VenuGoPal - 不用谢。:o) 只要小心重新编号问题即可。 - user1945782
太棒了,这帮助了我很多! - tomovam

2

由于我是按字符串字段而不是ID字母顺序排序,因此Count(*)和DCOUNT()方法对我无效。我的解决方案是编写一个返回行号的函数:

Original Answer翻译成"最初的回答"

Option Compare Database
Option Explicit
Private Rst As Recordset

Public Function GetRowNum(ID As Long) As Long
  If Rst Is Nothing Then
    Set Rst = CurrentDb.OpenRecordset("SELECT ID FROM FileList ORDER BY RealName")
  End If
  Rst.FindFirst "ID=" & ID
  GetRowNum = Rst.AbsolutePosition + 1
' Release the Rst 1 sec after it's last use
'------------------------------------------
  SetTimer Application.hWndAccessApp, 1, 1000, AddressOf ReleaseRst  
End Function


Private Sub ReleaseRst(ByVal hWnd As LongPtr, ByVal uMsg As Long, ByVal nIDEEvent As Long, ByVal dwTime As Long)
  KillTimer Application.hWndAccessApp, 1 
  Set Rst = Nothing
End Sub

1

我需要每个团队的最佳x分数结果。

当有相等分数的结果时,排名无法解决这个问题。因此,我需要一个recordnumber

我在Access中制作了一个VBA函数来创建一个在ID更改时重置的recordnumber

您必须查询此查询,并使用recordnumber <= x进行筛选以获取每个团队的得分。

NB Access会更改记录编号:

  1. 当您查询按记录号过滤的查询时
  2. 当您过滤掉一些结果时
  3. 当您更改排序顺序时

这不是我想发生的事情。

通过使用临时表并保存recordnumbers和键或表中的额外字段来解决了这个问题。

SELECT ID, Points, RecordNumberOffId([ID}) AS Recordnumber
FROM Team ORDER BY ID ASC, Points DESC;

它使用三个模块级变量来记住调用之间的信息。
Dim PreviousID As Long
Dim PreviousRecordNumber As Long
Dim TimeLastID As Date

Public Function RecordNumberOffID(ID As Long) As Long 
'ID is sortgroup identity
'Reset if last call longer dan nn seconds in the past
If Time() - TimeLastID > 0.0003 Then '0,000277778 = 1 second
    PreviousID = 0
    PreviousRecordNumber = 0
End If
If ID <> PreviousID Then
    PreviousRecordNumber = 0
    PreviousID = ID
End If
PreviousRecordNumber = PreviousRecordNumber + 1
RecordNumberOffID = PreviousRecordNumber
TimeLastID = Time()
End Function

0
在你想要排序的查询中创建一个新字段,并键入以下内容:
DCount("[你想要基于其进行排序的字段的名称]";"[当前查询的名称]";"[你想要基于其进行排序的字段的名称]>=" & [你想要基于其进行排序的字段的名称])
然后,你将会根据你选择的字段在查询中得到一个排序。

但是相等的值将获得相同的行号。 - undefined

0

非常感谢您提供的解决方案!DCount 对我也很有帮助!

我不得不使用日期列和唯一标识符的组合来进行排序(以及一些其他条件),所以这就是我最终做的事情: 1)我必须检查 DateColumnA 是否为空,然后检查 DateColumnB 是否为空,然后使用 DateColumnC;然后,如果多个记录具有相同的日期值,则它们都将具有相同的 ID! 2)因此,我想使用表的整数唯一 ID,并将其加上时间作为“分钟”。这将始终提供不同的结果。 3)最后,上述逻辑导致计数从 0 开始...所以只需加 1!

SELECT 
 1+DCount("[RequestID]","[Request]","Archived=0 and ProjectPhase <> 2 and iif(isnull(DateColumnA)=true,iif(isnull(DateColumnB)=true,DateColumnC,DateColumnB),DateColumnA)+(RequestID/3600) < #" & if(isnull(DateColumnA)=true,iif(isnull(DateColumnB)=true,DateColumnC,DateColumnB),DateColumnA) + (RequestID/3600) & "#") AS RowID, 
FROM 
 Request
ORDER BY 1

我希望这可以帮助你!

-1

我可能会迟到。只需在表中添加一个类型为AutoNumber的新字段ID即可。这将生成唯一的ID,并且可以在Access中使用。


3
如果数据集是静态的,你的说法是正确的。但如果查询结果或表格中的记录数量是动态的,这种方法就无效了。 - RazorSky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接