【问题标题】:Row numbers in query result using Microsoft Access使用 Microsoft Access 查询结果中的行号
【发布时间】:2013-06-21 04:29:00
【问题描述】:

我总是在 sql server 中使用这个查询来获取表中的行号:

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

现在我在 Access 2010 中工作,这似乎不起作用。在 Access 中是否有此查询的替代品?

【问题讨论】:

    标签: sql ms-access


    【解决方案1】:

    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
    

    【讨论】:

    • 我知道我会因此而被否决,但说真的,对于像 Access 这样长期流行的应用程序中的基本问题,这种解决方法不应该是必需的。
    • @DamienGolding 您当然可以尝试使用 DCount 更“直截了当”的方法,但正如评论所说,这不会有效地工作......虽然 Access 很受欢迎,但它更像是一个桌面工具,并不打算像真正的服务器解决方案那样功能齐全。
    • @PinnyM,您描述的需要第 15 个数字的方法是否也适用于日期?谢谢。
    • @JM1 当然,任何可以通过 ORDER BY 排序的东西都应该可以工作,包括日期。
    【解决方案2】:

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

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

    【讨论】:

    • 这个解决方案很简单,但似乎效率很低。我不会在大型数据集上尝试!
    【解决方案3】:

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

    【讨论】:

    • 虽然您对静态数据集是正确的。如果您的查询中有动态数量的记录,甚至是一个不断变化的表,那么这是行不通的。
    【解决方案4】:

    我需要每支球队获得最好的 x 分结果。

    当有相同点的结果时,排名并不能解决这个问题。 所以我需要一个recordnumber

    我在 Access 中创建了一个 VBA 函数来创建一个recordnumber,它会在 ID 更改时重置。

    您必须使用 where recordnumber &lt;= x 查询此查询以获得每个团队的积分。

    NB Access 更改记录号

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

    这不是我认为会发生的事情。

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

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

    在调用之间使用 3 个模块级变量来记忆

    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
    

    【讨论】:

      【解决方案5】:

      虽然这是一个老问题,但这对我有用,但我从未测试过它的效率......

      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 是根据其实际值和小于它的值计算的。
      • 此方法可应用于任何(主键)类型(例如Number、String 或Date)。
      • 此方法相当与 SQL 无关,或者只需要很少的调整。

      最后的想法

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

      ID     Description    ROWID
      aaa    Aardvark           1
      bbb    Bear               2
      ccc    Canary             3
      

      如果我要插入:bba Boar,那么Canary RowID 将会改变...

      ID     Description    ROWID
      aaa    Aardvark           1
      bbb    Bear               2
      bba    Boar               3
      ccc    Canary             4
      

      【讨论】:

      • @VenuGoPal - 不客气。 :o) 请注意重新编号问题。
      【解决方案6】:

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

      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
      

      【讨论】:

        【解决方案7】:

        感谢您提供上述解决方案! 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
        

        希望对你有帮助!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-12-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多