使用forloops vba-excel将数据转换为面板格式

时间:2016-05-27 08:01:53

标签: vba excel-vba data-cleaning excel

我的数据集如下:

AUS, UK, USA, GERMANY, FRANCE, MEXICO, DATE
R1, R1,   R1,    R1  ,   R1  , R1    ,  1
R2, R2,   R2,    R2  ,   R2  , R2    ,  2
...

等等。我想转换它看起来像

COUNTRY, RETURNS, DATE, 
AUS,     R1,       1
AUS,     R2,       2
...,    ...,     ...,
UK,     R1,        1,
UK,     R2,        2,
...     ...      ...,
MEXICO, R1,        1,
MEXICO, R2,        2,
...     ...      ...

我觉得这应该是一个简单的嵌套forloop。

我试过了:

    sub panel()
'dim variables
Dim i As Integer
Dim j As Integer
Dim reps As Integer
Dim country As String
Dim strfind As String
Dim obs As Integer

'count the number of countries
reps = Range("D1:AL1").Columns.Count

'count the number of observations per country
obs = Range("C4:C5493").Rows.Count

'copy and paste country into panel format
For i = 1 To reps
    'set country name
    country =Range("D1").Cells(1, i)
    For j = 1 To obs
    'copy and paste country values
    Range("AS2").Cells(j, 1) = country
    Next j
Next i

但是在j循环结束并且设置了新的国家/地区名称后,新值将替换第一批单元格中的旧值。

2 个答案:

答案 0 :(得分:1)

考虑使用UNION查询的SQL解决方案来选择长格式的每个列。如果使用Excel for PC,Excel可以通过ADO连接到Jet / ACE SQL引擎(Windows .dll文件),并在当前工作簿的工作表上运行SQL查询。

使用这种方法,您可以避免任何for循环,嵌套if/then逻辑以及所需输出的其他数据操作需求。下面的示例假定数据驻留在名为 DATA 的选项卡中,以及一个名为 RESULTS 的空选项卡。

Sub RunSQL()    
    Dim conn As Object, rst As Object
    Dim strConnection As String, strSQL As String
    Dim i As Integer

    Set conn = CreateObject("ADODB.Connection")
    Set rst = CreateObject("ADODB.Recordset")

    ' CONNECTION STRINGS (TWO VERSIONS)
'    strConnection = "DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _
'                      & "DBQ=C:\Path\To\Workbook.xlsm;"
    strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" _
                       & "Data Source='C:\Path\To\Workbook.xlsm';" _
                       & "Extended Properties=""Excel 8.0;HDR=YES;"";"        
    strSQL = " SELECT 'AUS' AS COUNTRY, AUS AS RETURNS, [DATE] FROM [DATA$]" _
            & " UNION ALL SELECT 'UK', UK AS Country, [DATE] FROM [DATA$]" _
            & " UNION ALL SELECT 'USA', USA AS Country, [DATE] FROM [DATA$]" _
            & " UNION ALL SELECT 'GERMANY', GERMANY AS Country, [DATE] FROM [DATA$]" _
            & " UNION ALL SELECT 'FRANCE', FRANCE AS Country, [DATE] FROM [DATA$]" _
            & " UNION ALL SELECT 'MEXICO', MEXICO AS Country, [DATE] FROM [DATA$];"

    ' OPEN CONNECTION & RECORDSET
    conn.Open strConnection
    rst.Open strSQL, conn

    ' COLUMN HEADERS
    For i = 1 To rst.Fields.Count
        Worksheets("RESULTS").Cells(1, i) = rst.Fields(i - 1).Name
    Next i        
    ' DATA ROWS
    Worksheets("RESULTS").Range("A2").CopyFromRecordset rst

    rst.Close: conn.Close    
    Set rst = Nothing: Set conn = Nothing    
End Sub

输出

COUNTRY     RETURNS     DATE
AUS         R1          1
AUS         R2          2
UK          R1          1
UK          R2          2
USA         R1          1
USA         R2          2
GERMANY     R1          1
GERMANY     R2          2
FRANCE      R1          1
FRANCE      R2          2
MEXICO      R1          1
MEXICO      R2          2

答案 1 :(得分:0)

好的,我修好了。可能不是最好的代码,但它有效:)。

Sub replicate_dates()
'declare variables
Dim i As Double
Dim j As Double
Dim reps As Integer
Dim country As String
Dim strfind As String
Dim obs As Integer
'set strfind value
strfind = "-DS Market"

'count the number of countries
reps = Range("D1:AL1").Columns.Count

'count the number of observations per country
obs = Range("C4:C5493").Rows.Count

i = 0
'copy and paste country into panel format
For k = 1 To reps
    'set country name and clean string
    country = Replace(Range("D1").Cells(1, k), strfind, "")
    For j = i + 1 To obs + i
    'copy and paste country values
    Range("AS5").Cells(i, 1) = country
    i = 1 + i
    Next j

Next k

End Sub

编辑:Nvm,这在一个非常具体的案例之外无效。