规范化Excel表格

时间:2016-09-02 19:34:33

标签: excel normalization

我有从另一个系统导出的excel表。我需要将其上传到数据库中,并且正在寻找一种规范化的方法。

目前的结构:

customerid   date1   date2   date3 ... date85
1             1/1     1/4     2/4       
2             3/1
3             4/1     4/12

需要转换为:

customerid     date
1               1/1
1               1/4
1               2/4
2               3/1
3               4/1
3               4/12

我在Mac上并且拥有2016年的优秀成绩。我没有像电源枢轴这样的插件。

4 个答案:

答案 0 :(得分:1)

您可以使用数据透视表向导(这不是附加组件,它是内置的Excel功能):

  1. 按Alt,D,P打开数据透视表向导
  2. 选择“多个Consolodation范围”,然后单击“下一步”
  3. 选择“我将创建页面字段”,然后单击“下一步”
  4. 将光标置于“范围”文本框中,选择您的数据范围,包括行标题(在您的示例中,我相信它将是A1:CH4),然后单击“添加”,然后单击“下一步”
  5. 选择“新工作表”,然后单击“完成”
  6. 在生成的新工作表中,双击右下角的单元格(“Total Total”单元格)。这将打开包含您的规范化数据的第二个新工作表。
  7. 要删除第二个新工作表中的空白值,请单击“值”列中的过滤器图标,然后取消选中“(空白)”复选框
  8. 将结果数据复制到剪贴板,并粘贴到需要的任何位置。

答案 1 :(得分:0)

假设customerid在A1中,请在第2行的第2行中尝试(我没有!)

=OFFSET(A$2,INT((ROW()-2)/85),)  

在另一栏中:

 =OFFSET(B$2,INT(ROW()/85),MOD(ROW()-2,85),)  

向下复制以适应,选择公式单元格,复制,粘贴特殊...,值顶部,然后过滤以删除另一个'柱。

请注意,如果在一张纸上执行此操作,因为删除行也可能会删除一些源数据。

添加标签。

答案 2 :(得分:0)

这就是我想出的结果,我希望VBA在Mac上没有太大的不同,然后它在PC上,否则这可能不起作用。

代码被公平评论,但可以随意询问是否有问题。

'Helper function to find the last Column
Public Function getLastColumn(strSheet, strColum) As Integer
    Dim rng As Range
    Set rng = Sheets(strSheet).Cells.Find(What:="*", _
            After:=Sheets(strSheet).Range("A1"), _
            Lookat:=xlPart, _
            LookIn:=xlFormulas, _
            SearchOrder:=xlByColumns, _
            SearchDirection:=xlPrevious, _
            MatchCase:=False)

    If rng Is Nothing Then
        getLastColumn = 1
    Else
        getLastColumn = rng.Column
    End If
End Function

'Helper function to find the lastRow
Public Function getLastRow(strSheet, strColum) As Long
    Dim rng As Range: Set rng = Worksheets(strSheet).Range(strColum & "1")
    getLastRow = Worksheets(strSheet).Cells(Rows.Count, rng.Column).End(xlUp).row
End Function

Public Sub Normalize_Table()
    Dim LastRow As Long: LastRow = getLastRow("Sheet1", "A") ' First Parameter is the Sheet Name,
                                                             ' Second is the column you want to count
    Dim LastColumn As Integer: LastColumn = getLastColumn("Sheet1", "A")
    Dim RowCounter As Long: RowCounter = 1 ' Starting Row
    Dim RowID As Variant ' RowID, basically this is the repeated Column 1 value
    Dim row As Object
    Dim col As Object
    Dim rng As Range: Set rng = Sheets("Sheet1").Range(Sheets("Sheet1").Cells(1, 1), _
                                Sheets("Sheet1").Cells(LastRow, LastColumn)) ' Get the range you want to Normalize to another sheet/range

    'Iterate the range, go through each row, and each column
    'Making a new row for each column value, only update the value
    'of the first column when a start a new row
    For Each row In rng.Rows
        RowID = rng.Cells(row.row, 1)
        For Each col In rng.Columns
            'Assuming you want to add this to a new sheet, Let's say "Sheet2"
            Sheets("Sheet2").Cells(RowCounter, 1) = RowID
            If col.Column > 1 Then
                Sheets("Sheet2").Cells(RowCounter, 2) = rng(row.row, col.Column)
                RowCounter = RowCounter + 1
            End If
        Next
    Next       
End Sub

答案 3 :(得分:0)

这是一种VBA方法,即使在大型数据库上也应​​该非常快速地运行。 请注意,您必须按照该模块中的说明重命名类模块。

另请注意,您可能需要重命名wsSrc和wsRes - 包含源数据的工作表以及您希望结果的位置。

在常规模块的末尾附近还有一个区域,我做了一些基本的格式化。如果需要的话,你当然可以把它调整到漂亮的东西。

班级单元

Option Explicit

'Rename cCustDTS

Private pID As String
Private pDT As Date
Private pDTs As Collection

Private Sub Class_Initialize()
    Set pDTs = New Collection
End Sub

Public Property Get ID() As String
    ID = pID
End Property
Public Property Let ID(Value As String)
    pID = Value
End Property

Public Property Get DT() As Date
    DT = pDT
End Property
Public Property Let DT(Value As Date)
    pDT = Value
End Property

Public Property Get DTs() As Collection
    Set DTs = pDTs
End Property
Public Function ADDdt(Value As Date)
    pDTs.Add Value
End Function

常规模块

Option Explicit
Sub NormalizeDates()
    Dim vSrc As Variant, vRes As Variant
    Dim wsSrc As Worksheet, wsRes As Worksheet, rRes As Range
    Dim cCD As cCustDTS, colCD As Collection
    Dim I As Long, J As Long, LineCount As Long
    Dim LastRow As Long, LastCol As Long
    Dim V As Variant, W As Variant

'Set Source and Results Worksheets and Ranges
Set wsSrc = Worksheets("sheet1")
Set wsRes = Worksheets("sheet2")
    Set rRes = wsRes.Cells(1, 1)

'Get Source Data
With wsSrc
    LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
    LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
    vSrc = .Range(.Cells(1, 1), .Cells(LastRow, LastCol))
End With

'Collect and organize the data
Set colCD = New Collection
For I = 2 To UBound(vSrc, 1) 'Skip the first row
    Set cCD = New cCustDTS
    With cCD
        .ID = vSrc(I, 1)
        For J = 2 To UBound(vSrc, 2)
            If IsDate(vSrc(I, J)) Then
                .DT = vSrc(I, J)
                .ADDdt .DT
            End If
        Next J
        colCD.Add cCD
        LineCount = LineCount + .DTs.Count
    End With
Next I

'Organize the data for output
ReDim vRes(0 To LineCount, 1 To 2)
    vRes(0, 1) = "Customer ID"
    vRes(0, 2) = "Date"
    I = 0
For Each V In colCD
    For Each W In V.DTs
        I = I + 1
        vRes(I, 1) = V.ID
        vRes(I, 2) = W
    Next W
Next V

'Write to the output sheet and format
Set rRes = rRes.Resize(rowsize:=UBound(vRes, 1) + 1, columnsize:=UBound(vRes, 2))
With rRes
    .EntireColumn.Clear
    .Value = vRes
    With .Rows(1)
        .Font.Bold = True
        .HorizontalAlignment = xlCenter
    End With
    With .Columns(2)
        .NumberFormat = "m/d"
    End With
    .EntireColumn.AutoFit
    .Columns(2).ColumnWidth = .Columns(2).ColumnWidth * 2
End With

End Sub