使用VB代码

时间:2017-05-30 15:56:48

标签: vba ms-access access-vba

我有一个表格,其中填充了分隔文本文件中的数据。数据来自另一个系统,我无法修改它在我导入的文本文件中的生成方式。将数据导入访问后,它不是标准化的方式。前两列数据是日期范围,第三列是位置代码,其余54列包含每个位置的特定数据。我需要找到每条记录的前五个值,以便将它们放入报告中。

我在另一个thread提出了这个问题,但无法找到解决方案。在那个帖子中,有人建议我使用联合查询。它看起来完美无缺,但你只能使用50个工会,而且我有很多领域。

现在我试图在访问中使用VB代码来转置表。我正在处理从page检索到的以下代码。它在执行时抛出错误。我无法弄清楚问题是什么。我知道这是一个语法错误或创建对象,但我已经尝试了我能想到的一切,但无法让它工作。此外,列标题将包含字符串信息所以我打算将变量更改为变量而不是整数?任何有关此代码的帮助,或有关如何从表中获得我想要的建议将不胜感激。

实际table的图片。

我收到错误 - > '运行时错误'3265':此集合中找不到项目。

Private Sub Command78_Click()


  Const cstrInputTable = "Base Period OT"
  Const cstrOutputTable As String = "Normalized Base Period OT"

  Dim dbs As DAO.Database
  Dim rstInput As DAO.Recordset
  Dim rstOutput As DAO.Recordset
  Dim intYear As Integer

  Set dbs = CurrentDb
  Set rstInput = dbs.OpenRecordset(cstrInputTable)
  Set rstOutput = dbs.OpenRecordset(cstrOutputTable)

  If Not rstInput.EOF Then
    ' For each column in the Input table, create a record in the output   table
    For intYear = 1990 To 2011
      rstInput.MoveFirst
      rstOutput.AddNew
        rstOutput![Year] = intYear

        ' Go through every record in the Input table
        Do
          rstOutput(rstInput![Data Type]) = rstInput(CStr(intYear))
          rstInput.MoveNext
        Loop Until rstInput.EOF

      rstOutput.Update
    Next intYear
  End If
  rstInput.Close
  rstOutput.Close
  dbs.Close

  MsgBox "Data Successfully Transformed"
  DoCmd.OpenTable cstrOutputTable

End Sub

2 个答案:

答案 0 :(得分:1)

仍不确定我是否完全理解您的输入和输出。我会试一试,你告诉我,如果我接近你正在寻找的东西。

您可以创建仅包含3个字段的“Temp”表,仅用于排序目的。然后,您可以遍历源表,并将位置,列标题(3个字母代码)和每个字段的值添加到“Temp”表中。

然后,您可以按值DESC排序并选择前5位。

Public Sub GetTopFive()
    On Error GoTo ErrProc

    Dim rs As DAO.Recordset
    Set rs = CurrentDb.OpenRecordset("SELECT Location, AMR, AXT, BRM, BMM, CSR, CTC " & _
                                     "FROM DataSource ORDER BY Location;", dbOpenSnapshot)

    If rs.EOF Then GoTo Leave
    With rs
        .MoveLast
        .MoveFirst
    End With

    Dim idx As Long
    For idx = 1 To rs.RecordCount
            AddToTempTable rs
           'Now the Temp table holds one Location, sorted by value
           'Selecting the top 5 records will give you what you're looking for
           'If that's the case, provide additional info on how to handle this 
           'as each location might have different field names.
        rs.MoveNext
    Next idx


Leave:
    On Error Resume Next
    rs.Close
    Set rs = Nothing
    On Error GoTo 0
    Exit Sub

ErrProc:
    MsgBox Err.Description, vbCritical
    Resume Leave
End Sub

'Add To Temp for sorting
Private Sub AddToTempTable(rs As DAO.Recordset)

    Dim fld As DAO.Field
    For Each fld In rs.Fields
        If fld.Name <> "Location" Then
            With CurrentDb.QueryDefs("qryAddToTemp")
                .Parameters("[prmLocation]").Value = rs!Location
                .Parameters("[prmFileldName]").Value = fld.Name
                .Parameters("[prmFieldValue]").Value = fld.Value
                .Execute dbFailOnError
            End With
        End If
    Next fld
End Sub

导入查询

PARAMETERS [prmLocation] Text ( 255 ), [prmFileldName] Text ( 255 ), [prmFieldValue] IEEESingle;
INSERT INTO tbTemp ( Location, [Field Name], [Field Value] )
SELECT [prmLocation] AS Location, [prmFileldName] AS [Field Name], [prmFieldValue] AS [Field Value];

临时表

Temp Table

更新

Public Sub GetTopFive()
    On Error GoTo ErrProc

    Dim rs As DAO.Recordset
    Set rs = CurrentDb.OpenRecordset("SELECT Location, AMR, AXT, BRM, BMM, CSR, CTC " & _
                                     "FROM DataSource ORDER BY Location;", dbOpenSnapshot)

    If rs.EOF Then GoTo Leave
    With rs
        .MoveLast
        .MoveFirst
    End With

    Dim rsTemp As DAO.Recordset, fld As DAO.Field, idx As Long
    Set rsTemp = CurrentDb.OpenRecordset("tbTemp")

    With rsTemp
        For idx = 1 To rs.RecordCount
            For Each fld In rs.Fields
                If fld.Name <> "Location" Then
                    .AddNew
                    .Fields("YourCodeColumnName").Value = fld.Name
                    .Fields(rs!Location).Value = fld.Value
                    .Update
                End If
            Next fld
            rs.MoveNext
        Next idx
    End With

Leave:
    On Error Resume Next
    rsTemp.Close
    Set rsTemp = Nothing
    rs.Close
    Set rs = Nothing
    On Error GoTo 0
    Exit Sub

ErrProc:
    MsgBox Err.Description, vbCritical
    Resume Leave
End Sub

答案 1 :(得分:0)

根据您提供的内容,一旦您了解了DAO Recordset对象的工作方式和参考字段&#34;表&#34,就有6种可能性,您将获得错误3265,其中4种具有相同的解决方案;他们代表着。

错误Item not found in this collection,给定您提供的代码表明您在记录集中引用了一个不存在的字段名称(列名)。或者,您正在引用数据库中不存在的表名。

由于您的代码是动态确定字段名称,并且您还没有提供表Base Period OTNormalized Base Period OT的结构,因此您必须自己完成部分内容。

以下是Recordset对象可能发生错误的4个地方以及您要查找的内容:

  1. rstOutput![Year] = intYear,您告诉Access您希望列名为&#34; Year&#34;存在于表Normalized Base Period OT中,并且您希望将当前值intYear插入该列。如果&#34;年&#34;不是该表中的列名,这就是问题所在。

  2. 3,&amp; 4. rstOutput(rstInput![Data Type]) = rstInput(CStr(intYear))在这一行代码中,您有3个可能的错误位置。

    一个。 rstInput![Data Type]Base Period OT是否包含名为&#34;数据类型&#34;?的列如果没有,这将是一个错误。在这里,您静态地提供了您希望在输入表中存在的列的名称。

    rstOutput(rstInput![Data Type])假设rstInput![Data Type]是有效列,该列中的值现在是您希望在Normalized Base Period OT中存在的列的名称。如果不是这样,那将是一个错误。在这里,您将动态提供您希望存在于输出表中的列的名称。

    ℃。 rstInput(CStr(intYear))Base Period OT是否包含当前值intYear的列(即该表是否包含在循环中定义的2011年到1990年的名称为1990,1991,1992等的列?)如果没有,这将是一个错误。在这里,您再次动态地提供您希望在输入表中存在的列的名称。

  3. 5&amp; 6.如果您的两个常量中指定的表格不存在,您也可能会在OpenRecordset命令上收到此错误。

    这解决了您的代码示例的问题,但未解决您为其他声明目的转换数据的方法是否正确,因为我们没有足够的其他信息。