2014-09-19 60 views
0

我有一些数据在Excel文件中有一些水平和垂直的尺寸。它看起来像这样:从Excel数据转换

enter image description here

这个数据必须被加载到一些BI系统。为此,我必须将数据转换为“表格样式”。换句话说,它应该在表中给出这样的:

enter image description here

我需要一些有效的算法,使这一转变。我知道的唯一一个就是从第一个单元格(100000)获取值,并从垂直和水平坐标(俄罗斯,人口,1900)中获取数值并插入第一行。然后再取另一个单元格等。

这将是少量的数据工作,但大量它的工作非常缓慢。你知道这种数据更复杂的算法吗?

+0

临时输出的行顺序是否重要?这是经常做的事情吗(你没有用[excel-vba]标记)? – pnuts 2014-09-19 20:11:43

+0

你有多少数据?如果你有100个国家,100多个指数,超过100年,你会接近Excel排行限制,在一组列中完成此操作。 – 2014-09-19 21:49:46

+0

如果我必须这样做,我会在一些模块中使用'python'来读写XLS文件。 – 2014-09-20 00:59:23

回答

2

用VBA做这件事有几种方法。在这个解决方案中,我首先创建一个名为Country的用户定义Object,其中包含四个属性:Name,Index,YR和Quantity。没有必要这样做;但我最近一直在与这些工作,我认为它增加了代码的一些清晰度。

然后,我将源数据读入VBA数组(可以在一个步骤中完成),迭代数组以创建Country对象的集合。

然后我通过国家集合,将属性输出到结果数组中,我想要它们。

最后,结果数组输出到工作表 - 再次,只是一个步骤。

可以直接从Source数据数组转到Results数组,但我认为使用该对象更容易看到会发生什么。

人们也可能不打扰VBA阵列,但直接从一个工作表处理单元格到另一个。根据我的经验,这种方法至少比使用VBA阵列方法慢一个数量级。

根据数据库的大小,可能需要改进。一定要阅读代码中的评论。

要定义Country对象,请插入一个Class Module并将其重命名为Country。 在该模块中放置以下代码:

===================================== =====

Option Explicit 
Private pName As String 
Private pIndex As String 
Private pYr As Long 
Private pQuantity As Double 

Public Property Get Name() As String 
    Name = pName 
End Property 
Public Property Let Name(Value As String) 
    pName = Value 
End Property 

Public Property Get Index() As String 
    Index = pIndex 
End Property 
Public Property Let Index(Value As String) 
    pIndex = Value 
End Property 

Public Property Get Yr() As Long 
    Yr = pYr 
End Property 
Public Property Let Yr(Value As Long) 
    pYr = Value 
End Property 

Public Property Get Quantity() As Double 
    Quantity = pQuantity 
End Property 
Public Property Let Quantity(Value As Double) 
    pQuantity = Value 
End Property 

====================================== =======

然后,将常规模块有将此代码:

======================= ================

Option Explicit 
Sub TransformData() 
    Dim wsSrc As Worksheet 'Data Source 
    Dim wsRes As Worksheet, rRes As Range 'Results go here 
    Dim vSrc As Variant 'Actual data goes into this array 
    Dim vRes() As Variant 'Results will go here before being written to worksheet 
    Dim cCTY As Country 'User defined object 
    Dim colCountries As Collection 
    Dim I As Long, J As Long 'counters 

Set wsSrc = Worksheets("Sheet2") '<--change these to whatever 
Set wsRes = Worksheets("Sheet3") 

Set rRes = wsRes.Range("A1") '<--1st cell of results array 

'read data into array 
With wsSrc 
    vSrc = .Range("A1").CurrentRegion '<--many ways to get this depending on your real data setup 
End With 

'iterate through Source and create collection of results 
Set colCountries = New Collection 
For I = 2 To UBound(vSrc, 1) '<--Rows 
    For J = 3 To UBound(vSrc, 2) '<--Columns 
     Set cCTY = New Country 
     With cCTY 
      .Name = vSrc(I, 1) 
      .Index = vSrc(I, 2) 
      .Yr = vSrc(1, J) 
      .Quantity = vSrc(I, J) 
     End With 
     colCountries.Add cCTY 
    Next J 
Next I 

'Results 
ReDim vRes(0 To colCountries.Count, 1 To 4) 

'Column Labels 
vRes(0, 1) = "Country" 
vRes(0, 2) = "Index" 
vRes(0, 3) = "Year" 
vRes(0, 4) = "Value" 

For I = 1 To colCountries.Count 
    With colCountries(I) 
     vRes(I, 1) = .Name 
     vRes(I, 2) = .Index 
     vRes(I, 3) = .Yr 
     vRes(I, 4) = .Quantity 
    End With 
Next I 

Set rRes = rRes.Resize(UBound(vRes, 1) + 1, UBound(vRes, 2)) 
rRes.EntireColumn.Clear 
rRes = vRes 
With rRes.Rows(1) 
    .Font.Bold = True 
    .HorizontalAlignment = xlCenter 
End With 
rRes.EntireColumn.AutoFit 

End Sub 

================================================ ====

确保正确定义工作表和范围以符合您的真实设置并运行宏。