【问题标题】:Displaying Row numbers column at runtime在运行时显示行号列
【发布时间】:2014-03-03 12:45:49
【问题描述】:

我有一个以 name, age, city 为列的员工表。我想在运行时为从 1 开始的行号显示一列。我在 Access 中使用 SQL。

【问题讨论】:

标签: sql ms-access row-number


【解决方案1】:

从您的查询中调用以下函数。

Public Function GetNextNum(str As String) As Long
    num = num + 1
    GetNextNum = num
End Function

需要注意的是,您必须至少有一个参数(即使您不需要),否则该函数只会被调用一次并为所有行返回 1。

在运行查询之前,将全局变量 num 设置为 0。

【讨论】:

    【解决方案2】:

    您只需要一个函数即可获得一个非常快速甚至“可分组”的行计数器,无论是否自动重置计数器。

    查看内嵌 cmets 了解典型用法:

    Public Function RowCounter( _
      ByVal strKey As String, _
      ByVal booReset As Boolean, _
      Optional ByVal strGroupKey As String) _
      As Long
    
    ' Builds consecutive RowIDs in select, append or create query
    ' with the possibility of automatic reset.
    ' Optionally a grouping key can be passed to reset the row count
    ' for every group key.
    '
    ' Usage (typical select query):
    '   SELECT RowCounter(CStr([ID]),False) AS RowID, *
    '   FROM tblSomeTable
    '   WHERE (RowCounter(CStr([ID]),False) <> RowCounter("",True));
    '
    ' Usage (with group key):
    '   SELECT RowCounter(CStr([ID]),False,CStr[GroupID])) AS RowID, *
    '   FROM tblSomeTable
    '   WHERE (RowCounter(CStr([ID]),False) <> RowCounter("",True));
    '
    ' The Where statement resets the counter when the query is run
    ' and is needed for browsing a select query.
    '
    ' Usage (typical append query, manual reset):
    ' 1. Reset counter manually:
    '   Call RowCounter(vbNullString, False)
    ' 2. Run query:
    '   INSERT INTO tblTemp ( RowID )
    '   SELECT RowCounter(CStr([ID]),False) AS RowID, *
    '   FROM tblSomeTable;
    '
    ' Usage (typical append query, automatic reset):
    '   INSERT INTO tblTemp ( RowID )
    '   SELECT RowCounter(CStr([ID]),False) AS RowID, *
    '   FROM tblSomeTable
    '   WHERE (RowCounter("",True)=0);
    '
    ' 2002-04-13. Cactus Data ApS. CPH
    ' 2002-09-09. Str() sometimes fails. Replaced with CStr().
    ' 2005-10-21. Str(col.Count + 1) reduced to col.Count + 1.
    ' 2008-02-27. Optional group parameter added.
    ' 2010-08-04. Corrected that group key missed first row in group.
    
      Static col      As New Collection
      Static strGroup As String
    
      On Error GoTo Err_RowCounter
    
      If booReset = True Then
        Set col = Nothing
      ElseIf strGroup <> strGroupKey Then
        Set col = Nothing
        strGroup = strGroupKey
        col.Add 1, strKey
      Else
        col.Add col.Count + 1, strKey
      End If
    
      RowCounter = col(strKey)
    
    Exit_RowCounter:
      Exit Function
    
    Err_RowCounter:
      Select Case Err
        Case 457
          ' Key is present.
          Resume Next
        Case Else
          ' Some other error.
          Resume Exit_RowCounter
      End Select
    
    End Function
    

    【讨论】:

      【解决方案3】:

      您有 5 种方法可用。

      仅报告 - 运行总和

      如果您将此信息用于 Access 报告,有一种简单的方法不需要 VBA 或花哨的 SQL。只需添加一个带有控制源集=1 的文本框,然后将Running Sum 设置为Over All,就完成了。

      下面列出的其余方法适用于表单/数据表/记录集

      相关子查询

      您可以执行相关子查询。这个解决方案是完全独立的,但不是很通用。应该是这样的:

      SELECT
        (
          SELECT COUNT(*)
          FROM Employees AS x
          WHERE x.EmployeeID <= e.EmployeeID
          ORDER BY x.EmployeeID
        ) AS RowNumber,
        e.EmployeeID
      FROM Employees AS e;
      

      请注意,由于相关子查询,性能会随着表中记录数量的增加而迅速下降。如果它不应该依赖于 EmployeeID 而是其他东西(例如 HireDate),您可能必须自定义 ORDER BY 子句以获得所需的数字分配

      VBA 函数来维护计数,只进记录集

      此方法执行速度更快,但只能使用一次;当然不在表单/数据表中,因为在您导航时会不断评估 VBA 函数。因此,这仅适用于以只进方式读取记录集时。使用标准 VBA 模块:

      Private Counter As Long
      
      Public Function ResetRowNumber() As Boolean
        Counter = 0
        ResetRowNumber = (Counter = 0)
      End Function
      
      Public Function GetRowNumber(PrimaryKeyField As Variant) As Long
        Counter = Counter + 1
        GetRowNumber = Counter
      End Function
      

      然后在查询中使用:

      SELECT 
        GetRowNumber([EmployeeID]) AS RowNumber,
        EmployeeID
      FROM Employees
      WHERE ResetRowNumber();
      

      注意使用WHERE 隐式调用ResetRowNumber 函数的技巧。请注意,这仅在只有一个查询处于活动状态时才有效;有多个采用行号的查询将导致不正确的结果。但是实现非常简单且速度更快。

      VBA 函数保持计数并保存赋值

      这比以前的方法更昂贵,但仍然比足够大的表的相关子查询解决方案便宜。这具有在表格/数据表中有用的优点,因为一旦给出数字,它就会再次给出。同样,在标准 VBA 模块中:

      Private NumberCollection As VBA.Collection
      
      Public Function ResetRowNumber() As Boolean
        NumberCollection = New VBA.Collection
        ResetRowNumber = (NumberCollection.Count = 0)
      End Function
      
      Public Function GetRowNumber(PrimaryKeyField As Variant) As Variant
        On Error Resume Next
      
        Dim Result As Long
        Result = NumberCollection(CStr(PrimaryKeyField))
        If Err.Number Then
          Result = 0
          Err.Clear
        End If
      
        If Result Then
          GetRowNumber = Result
        Else
          NumberCollection.Add NumberCollection.Count + 1, CStr(PrimaryKeyField)
          GetRowNumber = NumberCollection.Count
        End If
        If Err.Number Then
          GetRowNumber = "#Error " & Err.Description
        End If
      End Function
      

      输入参数PrimaryKeyValue 引用一个不可为空的列(根据定义应该是主键列),这一点很重要。否则,如果它已经被记录在案,我们将无法知道应该给出哪个数字。 SQL与之前的方法类似:

      SELECT 
        GetRowNumber([EmployeeID]) AS RowNumber,
        EmployeeID
      FROM Employees
      WHERE ResetRowNumber();
      

      与之前的方法一样,这一次只适用于一个查询。如果你需要多个查询,那么你需要两倍的层;一个集合来引用哪个查询的集合,然后检查该查询的集合。这可能会有点毛茸茸。您还可以通过Scripting.Dictionary 获得更多信息,所以这是另一种选择。

      还请注意,该函数现在返回 Variant,因为它可能会遇到意外错误。因为函数可以被调用多次,可能是数百甚至数千次,我们不能弹出一个消息框,所以我们可以模仿内置函数所做的并返回一个#Error,这与底层不兼容我们真正使用的Long 类型。

      升级到 SQL Server 或其他 RDBMS

      Access 是一种现象 RAD 工具,用于构建以数据为中心的应用程序。但是,您不一定要使用它的数据库引擎。您可以将您的数据迁移到一个免费的 RDBMS,使用 ODBC 链接并像以前一样继续使用您的 Access 应用程序,并受益于 SQL 的强大功能,包括窗口函数ROW_NUMBER(),它比 VBA 更容易实现.如果您想要做的不仅仅是获取行号,您可能需要考虑是否应该将数据迁移到不同的数据库引擎。

      更多参考,this may be helpful

      【讨论】:

        猜你喜欢
        • 2017-05-15
        • 2019-08-02
        • 2010-09-12
        • 1970-01-01
        • 1970-01-01
        • 2015-10-21
        相关资源
        最近更新 更多