简体   繁体   English

使用VB代码在Access中转置表

[英]Transpose a table in Access using VB code

I have a table that is populated with data from a delimited text file. 我有一个表,其中填充了定界文本文件中的数据。 The data comes from another system and I cannot modify how it is generated into the text file I am importing. 数据来自另一个系统,我无法修改将其生成为要导入的文本文件的方式。 Once the data is imported into access, it is not in a normalized fashion. 将数据导入访问后,就不能以标准化的方式进行访问。 The first two columns of data are date ranges, the third is a location code, the remaining 54 columns hold specific data for each location. 数据的前两列是日期范围,第三列是位置代码,其余54列包含每个位置的特定数据。 I need to find the top five values for each record so I can put them into a report. 我需要找到每个记录的前五个值,以便可以将它们放入报告中。

I had posed this question in another thread , but was unable to find a solution. 我在另一个线程中提出了这个问题,但是找不到解决方案。 In that thread, someone recommended that I used a union query. 在那个线程中,有人建议我使用联合查询。 It appeared that it was going to work perfectly, but you can only use 50 unions in access and I have to many fields. 看来它可以完美运行,但是您只能在访问中使用50个联合,而且我必须访问许多领域。

Now I am trying to use VB code in access to transpose the table. 现在,我试图在访问中使用VB代码来转置表。 I am working with the following code that I retrieved from this page . 我正在使用从此页面检索到的以下代码。 It is throwing an error on execution. 它在执行时引发错误。 I cannot figure out what the issue is. 我不知道是什么问题。 I know it is a syntax error or creating the object, but I have tried everything I can think of and cannot get it to work. 我知道这是语法错误或创建对象,但是我已经尝试了所有我能想到的并且无法使它正常工作。 Also, The column headers would contain string info so I was going to change the variable to a variant instead of an integer? 另外,列标题将包含字符串信息,因此我要将变量更改为变量而不是整数? Any help with this code, or suggestions regarding how to get what I want from the table would be appreciated. 此代码的任何帮助,或有关如何从表中获取我想要的东西的建议,将不胜感激。

Picture of actual table . 实际表的图片。

I am getting a error -> 'Run-time error '3265': Item not found in this collection. 我收到一个错误->'运行时错误'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

Still not sure I have fully understood your inputs and outputs. 仍然不确定我是否完全理解您的输入和输出。 I'll give it a try though and you let me know if I'm even close to what you're looking for. 不过,我会尝试一下,如果我与您要寻找的内容接近,您会告诉我。

You can create a "Temp" table with only 3 fields just for sorting purposes. 您可以创建仅包含3个字段的“临时”表,仅用于排序目的。 You can then loop through your source table and add Location, Column header (3 letter code) and the value of each field to the "Temp" table. 然后,您可以遍历源表并将“位置”,“列标题”(3个字母代码)和每个字段的值添加到“临时”表中。

You can then sort by value DESC and select the top 5. 然后,您可以按值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

Import query 导入查询

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 临时表

临时表

Update: 更新:

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

Based on what you have provided there are 6 possibilities of where you are getting error 3265, and 4 of them have the same solution, once you understand how DAO Recordset objects work and reference fields in the "Table" they represent. 根据所提供的信息,一旦了解了DAO Recordset对象的工作方式以及它们在“表”中所引用的字段,就可以从6265处获得3265错误的可能性,其中4种具有相同的解决方案。

The error Item not found in this collection , given the code you have presented indicates that you are referencing a field name (column name) in the recordset that does not exist. 给定您提供的代码, Item not found in this collection错误Item not found in this collection ,表示您正在引用的记录集中的字段名(列名)不存在。 Or, that you are referencing a table name that does not exist in the database. 或者,您正在引用数据库中不存在的表名。

Since your code is dynamically determining field names, and you haven't provided the structure of the tables Base Period OT or Normalized Base Period OT , you will have to figure part of this out on your own. 由于您的代码是动态确定字段名称的,并且您没有提供表Base Period OTNormalized Base Period OT的表结构,因此您必须自己弄清楚其中的一部分。

Here are the 4 places where the error could be occurring for the Recordset objects and what you are looking for: 这是Recordset对象可能出现的错误以及您要查找的4个地方:

  1. rstOutput![Year] = intYear , you are telling Access that you expect a column named "Year" to exist in your table Normalized Base Period OT and that you want to insert the current value of intYear into that column. rstOutput![Year] = intYear ,您要告诉Access您希望表Normalized Base Period OT存在一个名为“ Year”的列,并且您希望将intYear的当前值插入该列中。 If "Year" is not a column name in that table, this would be the problem. 如果“ Year”不是该表中的列名,则可能是问题所在。

  2. 3, & 4. rstOutput(rstInput![Data Type]) = rstInput(CStr(intYear)) In this single line of code, you have 3 possible locations for the error. rstOutput(rstInput![Data Type]) = rstInput(CStr(intYear))在此单行代码中,您有3个可能的错误位置。

    a. 一种。 rstInput![Data Type] Does the table Base Period OT contain a column named "Data Type"? rstInput![Data Type]Base Period OT是否包含名为“数据类型”的列? If not, this would be an error. 如果不是,这将是一个错误。 Here you are statically providing the name of the column that you expect to exist in the input table. 在这里,您静态地提供了您希望在输入表中存在的列的名称。

    b. b。 rstOutput(rstInput![Data Type]) Assuming that rstInput![Data Type] is a valid column, the value in that column is now the name of the column you are expecting to exist in Normalized Base Period OT . rstOutput(rstInput![Data Type])假设rstInput![Data Type]是有效的列,那么该列中的值现在就是您希望存在于Normalized Base Period OT中的列的名称。 If that is not true, this would be an error. 如果那不是真的,那将是一个错误。 Here, you are dynamically providing the name of the column that you expect to exist in the output table. 在这里,您正在动态提供您希望在输出表中存在的列的名称。

    c. C。 rstInput(CStr(intYear)) Does the table Base Period OT contain a column for the current value of intYear (ie does that table contain columns named 1990, 1991, 1992, etc through 2011 as defined in your loop?) If not, this would be an error. rstInput(CStr(intYear))表“ Base Period OT是否包含intYear当前值的intYear (即该表是否包含循环中定义的名为1990、1991、1992等至2011的列?)将是一个错误。 Here, again, you are dynamically providing the name of the column that you expect to exist in the input table. 再次在这里,您将动态提供您希望在输入表中存在的列的名称。

5 & 6. You could also receive this error on your OpenRecordset commands if the tables, named in your two constants don't exist. 5&6。如果在两个常量中命名的表不存在,您还可能在OpenRecordset命令上收到此错误。

This addresses the issue with your code sample, but does not address whether your approach to transform the data for your other stated purposes is correct or not as we do not have enough additional information. 这解决了您的代码示例的问题,但是由于我们没有足够的附加信息,因此未解决您为其他指定目的转换数据的方法是否正确。

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

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