在运行时显示行号列

时间:2014-03-03 12:45:50

标签: sql ms-access row-number

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

3 个答案:

答案 0 :(得分:1)

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

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

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

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

答案 1 :(得分:1)

你只需要一个功能来获得一个非常快速,甚至可以组合的"行计数器,有或没有自动重置计数器。

有关典型用法,请参阅内嵌评论:

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

答案 2 :(得分:0)

您有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;

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

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