Excel ou Access: como agrupar várias linhas em uma tabela e inserir conteúdo em colunas? (“Coluna dividida”)

0

Eu tenho uma tabela contendo dados de produtos vendidos (mostrados no exemplo à esquerda):

Colunas:
Número da encomenda
Nome do produto
Atributo - especifica o que é dado no seguinte campo "valor", e. g. Nome do cliente ou variante do produto
Valor - é o valor do atributo
Contagem - é o número de produtos desta variante vendidos na ordem

Issosignifica:OprodutoBtem2variantes"c" e "d" Observe que, na ordem 1, o produto B foi vendido apenas na variante d, porque a letra "N" no campo "D4" significa "nenhum". Note que no OrdnerNo 3 o Produto B foi vendido apenas na Variante c, porque para a Variante d o campo "D9" é "N" !! Isso é confuso, mas é a estrutura dos dados originais (que eu não posso mudar).

Eu preciso de uma maneira de converter a tabela à esquerda em uma tabela como a da direita:

  • uma linha para cada tipo de produto
  • Número do pedido
  • Nome do produto
  • Nome do cliente
  • Contagem (número de produtos vendidos neste pedido)
  • Variante - esse é o problema, pois ele precisa ser preenchido com

Assim, todas as linhas com o mesmo OrderNo e o mesmo produto devem ser agrupados em um e

Espero que esteja claro o que preciso. Eu tentei fazê-lo com tabelas dinâmicas, mas isso falha, como a contagem é sempre em cada linha, não importa se tem valor "N" ou não e para os produtos sem variantes há apenas uma linha para cada ordem, no entanto para produtos com variantes existem vários ...

Então, como eu poderia criar a tabela certa com uma macro VBA no MS Excel ou talvez haja um truque no MS Access para fazer isso diretamente ou com uma consulta SQL?

    
por MostlyHarmless 07.12.2012 / 17:20

1 resposta

1

Isso foi muito confuso, mas eu entendi. Cole o código no módulo. Certifique-se de estar na planilha principal para fazer a avaliação e executar o transformTable ().

Veja mais ou menos como funciona:

  • Percorra a lista
  • Ignore qualquer linha com N na coluna Valor
  • Crie uma coleção de pedidos
  • Se já existir um pedido (com base em OrderNo, Product e Count), adicione informações a ele (como informações de cliente ou variante)
  • Em seguida, percorra a coleção de pedidos e imprima em uma nova planilha

Espero que gostem.

Option Explicit

Public Type OrderInfo
    orderNo As Long
    product As String
    customer As String
    productVariant As String
    producctVariantName As String
    productCount As Long
End Type

Public Sub transformTable()
    Dim sh As Excel.Worksheet
    Dim orders() As OrderInfo

    Set sh = ActiveSheet
    orders = buildOrders(sh)
    Call createNewTable(orders)
End Sub

Private Sub createNewTable(ByRef orders() As OrderInfo)
    Application.ScreenUpdating = False

    Dim wb As Excel.Workbook
    Dim newSh As Excel.Worksheet
    Dim i As Long
    Dim curRow As Long

    curRow = 2
    Set wb = ThisWorkbook
    Set newSh = wb.Worksheets.Add

    newSh.Range("A1:F1").Value = Array("OrderNo", "Product", "Cust", "Count", "Variant", "Variant Name")

    For i = LBound(orders) To UBound(orders)
        newSh.Cells(curRow, "A").Value = orders(i).orderNo
        newSh.Cells(curRow, "B").Value = orders(i).product
        newSh.Cells(curRow, "C").Value = orders(i).customer
        newSh.Cells(curRow, "D").Value = orders(i).productCount
        newSh.Cells(curRow, "E").Value = orders(i).productVariant
        newSh.Cells(curRow, "F").Value = orders(i).producctVariantName

        curRow = curRow + 1
    Next i
    Application.ScreenUpdating = True
End Sub

Private Function buildOrders(ByRef sh As Excel.Worksheet) As OrderInfo()
    Dim lastRow As Long
    Dim i As Long
    Dim index As Long
    Dim indexFound As Long
    Dim orders() As OrderInfo

    lastRow = sh.Cells(sh.Rows.Count, 1).End(xlUp).Row
    ReDim orders(0)

    If (lastRow <= 1) Then
        buildOrders = orders
        Exit Function
    End If

    For i = 2 To lastRow
        If (sh.Cells(i, "D").Value <> "N") Then
            indexFound = findIndex(orders, sh.Cells(i, "A").Value, sh.Cells(i, "B").Value, sh.Cells(i, "E").Value)

            If (indexFound = -1) Then
                ' add new orderInfo
                ReDim Preserve orders(index)
                If (sh.Cells(i, "C").Value = "Cust") Then
                    orders(index) = createOrderInfo(sh.Cells(i, "A").Value _
                                            , sh.Cells(i, "B").Value _
                                            , sh.Cells(i, "E").Value _
                                            , sh.Cells(i, "D").Value)
                ElseIf (InStr(1, sh.Cells(i, "C").Value, "Variant", vbTextCompare) > 0) Then
                    orders(index) = createOrderInfo(sh.Cells(i, "A").Value _
                                            , sh.Cells(i, "B").Value _
                                            , sh.Cells(i, "E").Value _
                                            , productVariant:=Right(sh.Cells(i, "C").Value, 1) _
                                            , productVariantName:=sh.Cells(i, "D").Value)
                End If
                index = index + 1
            Else
                ' add customer or variant
                If (sh.Cells(i, "C").Value = "Cust") Then
                    orders(indexFound).customer = sh.Cells(i, "D").Value
                ElseIf (InStr(1, sh.Cells(i, "C").Value, "Variant", vbTextCompare) > 0) Then
                    orders(indexFound).productVariant = Right(sh.Cells(i, "C").Value, 1)
                    orders(indexFound).producctVariantName = sh.Cells(i, "D").Value
                End If
            End If

        End If

    Next i

    buildOrders = orders
End Function


Private Function createOrderInfo(ByVal orderNo As Long _
                                , ByRef product As String _
                                , ByVal productCount As Long _
                                , Optional ByRef customer As String = "" _
                                , Optional ByRef productVariant As String = "" _
                                , Optional ByRef productVariantName As String = "") As OrderInfo

    Dim oi As OrderInfo
    oi.orderNo = orderNo
    oi.product = product
    oi.productCount = productCount
    oi.customer = customer
    oi.productVariant = productVariant
    oi.producctVariantName = productVariantName

    createOrderInfo = oi
End Function



Private Function findIndex(ByRef orders() As OrderInfo _
                            , ByVal orderNo As Long _
                            , ByRef product As String _
                            , ByVal productCount As Long) As Long
    Dim i As Long

    For i = LBound(orders) To UBound(orders)
        If (orders(i).orderNo = orderNo And orders(i).product = product And orders(i).productCount = productCount) Then
            findIndex = i
            Exit Function
        End If
    Next i

    findIndex = -1
End Function
    
por 08.12.2012 / 19:45