VBA“激活加循环”冲突

时间:2017-04-15 15:39:36

标签: vba excel-vba iteration excel

我遇到的这个问题有三个文件:
“本地销售”,“全球销售”和“模板” 销售文件的第1列和第2列是相同的,3每个都有不同的信息。必须将所有数据复制到“模板”中的工作表。 第1列和第2列必须复制到相同位置(第1列和第2列),第3列必须是本地销售文件中的第3列,第4列必须是全局销售文件中的第3列。和我一起到目前为止?我希望如此......

这个例程第一次运行时,一切顺利,花花公子。它迭代第一个源文件中的所有列,并将它们粘贴到模板上。但是当fileNumber = 2时(当它应该对第二个源文件执行相同操作时),标记的行声称“需要一个对象”。 这让我疯了,因为我看不出第一次工作的原因,而不是第二次工作的原因!

我知道使用像“激活”这样的命令是错误的,但这是我第一次使用VBA,这是我看到的第一件事。请怜悯:))

Sub OpenFiles(ByVal fileNumber)

    If fileNumber = 1 Then
        Dim localFile As Workbook
        Set localFile = Application.Workbooks.Open("local sales.xls") ' here the path of "local sales.xls"
        Dim templateFile As Workbook
        Set templateFile = Application.Workbooks.Open("Template.xls") ' here the path of "Template.xls"
        localFile.Sheets("Sheet1").Activate
    Else
        Dim globalFile As Workbook
        Set globalFile = Application.Workbooks.Open("global sales.xls") ' here the path of "global sales.xls"
        globalFile.Sheets("Sheet1").Activate
    End If

    Dim lastColumnOnSource, lastRow, lastColumnOnDestiny As Long
    Dim textLastRow, textCol, areaToSelect, areaToPaste As String

    lastColumnOnSource = (ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column)
    lastRow = ActiveSheet.UsedRange.Rows.Count
    textLastRow = CStr(lastRow)

    For currentColumnOnSource = 1 To lastColumnOnSource
        If fileNumber = 1 Then
            localFile.Sheets("Sheet1").Activate
        Else
            globalFile.Sheets("Sheet1").Activate
        End If

        columnAsLetter = ColumnLetter(currentColumnOnSource)
        Let areaToSelect = columnAsLetter & "1:" & columnAsLetter & textLastRow
        Range(areaToSelect).Select
        Selection.Copy

        ' Moving to the template, to paste the data
        templateFile.Sheets("Data").Activate ' HERE IS THE ERROR
        lastColumnOnDestiny = ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column
        Dim cell1, cell2 As String
        Dim cell2AsRange As Range
        For currentColumnOnDestiny = 1 To lastColumnOnDestiny
            ' I take the first cell ("header") on the column and compare it until it's header
            ' matches the header on the column that is being copied and paste it there
            Let cell1 = columnAsLetter & "1"
            Let cell2 = ColumnLetter(currentColumnOnSource) & "1"
            If Range(cell1).Value = Range(cell2).Value Then
                ' select the column that cell 2 belongs on, to paste in it
                Let areaToPaste = cell1 & ":" & cell2
                Range(areaToPaste).Select
                Range(areaToPaste).PasteSpecial
                Exit For
            End If
        Next
    Next

    Application.CutCopyMode = False
    'Application.ActiveWorkbook.Save

End Sub

2 个答案:

答案 0 :(得分:1)

正如Rich Holton指出的那样,除非templateFile为1,否则你没有为fileNumber赋值。因此,当你到达templateFile.Sheets("Data").Activate语句时,它不知道是什么templateFile是。

最简单的更改只是在TemplateFile声明中添加If作业。

Dim templateFile As Workbook
If fileNumber = 1 Then
    Dim localFile As Workbook
    Set localFile = Application.Workbooks.Open("local sales.xls") ' here the path of "local sales.xls"
    Set templateFile = Application.Workbooks.Open("Template.xls") ' here the path of "Template.xls"
    localFile.Sheets("Sheet1").Activate
Else
    Dim globalFile As Workbook
    Set globalFile = Application.Workbooks.Open("global sales.xls") ' here the path of "global sales.xls"
    globalFile.Sheets("Sheet1").Activate
    Set templateFile = Application.Workbooks("Template.xls") ' here the path of "Template.xls"
End If

这将解决您的直接问题,但我怀疑当您到达执行复制/粘贴的代码部分时,您将遇到问题。据我所知,您的第二个文件的详细信息将覆盖您从第一个文件中获得的内容,但您的问题不够明确,我无法为您修复该代码。 (您的问题只讨论了文件1中第3列到第3列的第3列,以及文件2中的第3列到第4列 - 但您的代码看起来似乎正在尝试处理比此更多的列。)

答案 1 :(得分:0)

您可以使用ADODB对Global SalesTemplate工作簿进行SQL查询,然后将结果保存到SELECT A.Field1 AS F1, A.Field2 AS F2, B.Field2 AS F3 FROM Table1 AS A INNER JOIN Table2 AS B 工作簿中。

典型的INNER JOIN查询是:

SELECT
A.Field1 AS F1, A.Field2 AS F2, B.Field2 AS F3
FROM Table1 AS A
LEFT JOIN Table2 AS B
ON A.Field1 = B.Field1
UNION
SELECT
B.Field1 AS F1, A.Field2 AS F2, B.Field2 AS F3
FROM Table1 AS A
RIGHT JOIN Table2 AS B
ON A.Field1 = B.Field1

如果要组合来自两个源的数据,即使记录的某些字段为空,也可以尝试FULL JOIN查询。 Jet SQL不支持FULL JOIN,所以有一个解决方法,工会左右连接(注意非不同来源丢失重复):

Option Explicit

Sub JoinQuery()

    Dim sGlobalDataPath As String
    Dim sLocalDataPath As String
    Dim sTemplatePath As String
    Dim sGlobalDataSheet As String
    Dim sLocalDataSheet As String
    Dim sTemplateSheet As String
    Dim sProvider As String
    Dim sType As String
    Dim sGlobalData As String
    Dim sLocalData As String
    Dim sConnection As String
    Dim oTargetWorkbook As Workbook
    Dim sQuery As String
    Dim oConnection As Object
    Dim oRecordset As Object

    ' Put your paths and sheet names below
    ' Set path to Global Sales source file
    sGlobalDataPath = ThisWorkbook.Path & "\Global Sales.xlsx"
    sGlobalDataSheet = "Sheet1"
    ' Set path to Local Sales source file
    sLocalDataPath = ThisWorkbook.Path & "\Local Sales.xlsx"
    sLocalDataSheet = "Sheet1"
    ' Set path to Local Sales source file
    sTemplatePath = ThisWorkbook.Path & "\Template.xlsx"
    sTemplateSheet = "Sheet1"

    ' Create connection string to open ADODB.Connection
    GetConnOpts ThisWorkbook.FullName, sProvider, sType
    sConnection = _
        sProvider & _
        "Data Source='" & ThisWorkbook.FullName & "';" & _
        "Mode=Read;" & _
        "Extended Properties=""" & sType & """;"
    ' Open connection
    Set oConnection = CreateObject("ADODB.Connection")
    oConnection.Open sConnection

    ' Create connection strings for source files
    GetConnOpts sGlobalDataPath, sProvider, sType
    sGlobalData = "[" & sGlobalDataSheet & "$] IN '" & sGlobalDataPath & "' " & _
        "[" & sType & sProvider & "Mode=Read;Extended Properties=""HDR=YES;""] "
    GetConnOpts sLocalDataPath, sProvider, sType
    sLocalData = "[" & sLocalDataSheet & "$] IN '" & sLocalDataPath & "' " & _
        "[" & sType & sProvider & "Mode=Read;Extended Properties=""HDR=YES;""] "

    ' Create INNER JOIN query string
    sQuery = _
        "SELECT " & _
        "G.CustomerName, G.ContactName, G.Qty AS GlobalQty, L.Qty AS LocalQty " & _
        "FROM " & _
        "(SELECT * FROM " & sGlobalData & ") AS G " & _
        "INNER JOIN " & _
        "(SELECT * FROM " & sLocalData & ") AS L " & _
        "ON G.ContactName = L.ContactName AND G.CustomerName = L.CustomerName;"

    ' Execute query
    Set oRecordset = oConnection.Execute(sQuery)
    ' Open target workbook for output
    Set oTargetWorkbook = Application.Workbooks.Open(sTemplatePath)
    ' Output resulting recordset
    RecordsetToWorksheet oTargetWorkbook.Sheets(sTemplateSheet), oRecordset
    ' Save and close target workbook
    oTargetWorkbook.Save
    oTargetWorkbook.Close
    ' Close connection
    oConnection.Close

End Sub

Sub GetConnOpts(sFile As String, sProvider As String, sType As String)

    Select Case LCase(Mid(sFile, InStrRev(sFile, ".")))
        Case ".xls"
            sProvider = "Provider=Microsoft.Jet.OLEDB.4.0;"
            sType = "Excel 8.0;"
        Case ".xlsm"
            sProvider = "Provider=Microsoft.ACE.OLEDB.12.0;"
            sType = "Excel 12.0 Macro;"
        Case ".xlsx", ".xlsb"
            sProvider = "Provider=Microsoft.ACE.OLEDB.12.0;"
            sType = "Excel 12.0;"
        Case Else
            sProvider = ""
            sType = ""
    End Select

End Sub

Sub RecordsetToWorksheet(oSheet As Worksheet, oRecordset As Object)

    Dim i As Long

    With oSheet
        .Cells.Delete
        For i = 1 To oRecordset.Fields.Count
            .Cells(1, i).Value = oRecordset.Fields(i - 1).Name
        Next
        .Cells(2, 1).CopyFromRecordset oRecordset
        .Cells.Columns.AutoFit
    End With

End Sub

以下示例代码显示了如何完成INNER JOIN查询:

sQuery = ...

要使FULL JOIN使用以下代码替换字符串 ' Create simplified FULL JOIN query string sQuery = _ "SELECT " & _ "G.CustomerName, G.ContactName, G.Qty AS GlobalQty, L.Qty AS LocalQty " & _ "FROM " & _ "(SELECT * FROM " & sGlobalData & ") AS G " & _ "LEFT JOIN " & _ "(SELECT * FROM " & sLocalData & ") AS L " & _ "ON G.CustomerName = L.CustomerName AND G.ContactName = L.ContactName " & _ "UNION " & _ "SELECT " & _ "L.CustomerName, L.ContactName, G.Qty AS GlobalQty, L.Qty AS LocalQty " & _ "FROM " & _ "(SELECT * FROM " & sGlobalData & ") AS G " & _ "RIGHT JOIN " & _ "(SELECT * FROM " & sLocalData & ") AS L " & _ "ON G.CustomerName = L.CustomerName AND G.ContactName = L.ContactName"

Global Sales.xlsx

我使用示例源文件Local Sales.xlsxTemplate.xlsx和输出.xlsm的文件测试了代码。所有这些文件都与Global Sales.xlsx文件位于同一文件夹中,并带有上述代码。 Local Sales.xlsx的内容是:

Global Sales.xlsx

Template.xlsx

Local Sales.xlsx

INNER JOIN的输出.xlsb为:

output for INNER JOIN

FULL JOIN的输出是:

output for FULL JOIN

您可以使用.xlsm.xls.xlsx以及#include<pthread.h> #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<ncurses.h> const unsigned int NUM_OF_THREADS = 9; typedef struct thread_data_s { char *ptr; int row_num; } thread_data_t; void report(const char *s,int w,int q); void* row_check(void* data) { thread_data_t *my_data_ptr = data; int j, flag; flag=0x0000; for(j = 0; j < 9; j++) { flag |= 1u << ( (my_data_ptr->ptr)[j] - 1 ); if (flag != 0x01FF){ report("row", my_data_ptr->row_num, j-1); } } return NULL; } void report(const char *s,int w,int q) { printf("\nThe sudoku is INCORRECT"); printf("\nin %s. Row:%d,Column:%d",s,w+1,q+1); getchar(); exit(0); } int main(int argc, char* argv[]) { int i,j; char arr1[9][9]; FILE *file = fopen(argv[1], "r"); if (file == 0) { fprintf(stderr, "failed"); exit(1); } int col=0,row=0; int num; while(fscanf(file, "%c ", &num) ==1) { arr1[row][col] = num; col++; if(col ==9) { row++; col = 0; } } fclose(file); int n; thread_data_t data[NUM_OF_THREADS]; pthread_t tid; pthread_attr_t attr; for(n=0; n < NUM_OF_THREADS; n++) { data[n].ptr = &arr1[n][0]; data[n].row_num = n; pthread_create(&tid, &attr, row_check, &data[n]); } for(n=0; n < NUM_OF_THREADS; n++) { pthread_join(tid, NULL); } return 0; }