繁体   English   中英

使用VB代码在Access中转置表

[英]Transpose a table in Access using VB code

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

我在另一个线程中提出了这个问题,但是找不到解决方案。 在那个线程中,有人建议我使用联合查询。 看来它可以完美运行,但是您只能在访问中使用50个联合,而且我必须访问许多领域。

现在,我试图在访问中使用VB代码来转置表。 我正在使用从此页面检索到的以下代码。 它在执行时引发错误。 我不知道是什么问题。 我知道这是语法错误或创建对象,但是我已经尝试了所有我能想到的并且无法使它正常工作。 另外,列标题将包含字符串信息,因此我要将变量更改为变量而不是整数? 此代码的任何帮助,或有关如何从表中获取我想要的东西的建议,将不胜感激。

实际表的图片。

我收到一个错误->'运行时错误'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

仍然不确定我是否完全理解您的输入和输出。 不过,我会尝试一下,如果我与您要寻找的内容接近,您会告诉我。

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

然后,您可以按值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];

临时表

临时表

更新:

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

根据所提供的信息,一旦了解了DAO Recordset对象的工作方式以及它们在“表”中所引用的字段,就可以从6265处获得3265错误的可能性,其中4种具有相同的解决方案。

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

由于您的代码是动态确定字段名称的,并且您没有提供表Base Period OTNormalized Base Period OT的表结构,因此您必须自己弄清楚其中的一部分。

这是Recordset对象可能出现的错误以及您要查找的4个地方:

  1. rstOutput![Year] = intYear ,您要告诉Access您希望表Normalized Base Period OT存在一个名为“ Year”的列,并且您希望将intYear的当前值插入该列中。 如果“ Year”不是该表中的列名,则可能是问题所在。

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

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

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

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

5&6。如果在两个常量中命名的表不存在,您还可能在OpenRecordset命令上收到此错误。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM