如何按特定列值转置 header 行值组
How to Transpose header row value group by particular column value
我在 excel 中有一些数据,格式如下:
Cust_Name Prod1 Prod2 Prod3 Prod4 Prod5
A 0 100 120 0 0
B 145 120 168 0 200
C 350 300 0 340 0
我需要将以下格式转换为below-mentioned报告格式。
我想通过 Cust_Name 转置列组中的那些产品,其值 >0 否则它不应成为最终输出报告的一部分。
我尝试了很多枢轴选项,但都没有用。
所需输出:
Cust_Name Product Price
A Prod2 100
Prod3 120
Total A - 220
B Prod1 145
Prod2 120
Prod3 168
Prod5 200
Total B - 633
C Prod1 350
Prod2 300
Prod4 340
Total C - 890
您可以使用 PowerQuery 执行此操作。
Select 源数据中的任何单元格。使用数据>获取并转换数据>来自 Table/Range.
PowerQuery 编辑器将打开,如下所示:
Select Cust_Name 列通过单击 header 列。使用转换>逆透视列>逆透视其他列:
此时,可选择过滤“值”列以排除 0。
现在使用“开始”>“关闭并加载”将数据放回您的工作簿。
您现在可以创建数据透视表 table 来获取小计:
这是 PowerQuery 编辑器中“高级编辑器”对话框的查询:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Cust_Name", type text}, {"Prod1", Int64.Type}, {"Prod2", Int64.Type}, {"Prod3", Int64.Type}, {"Prod4", Int64.Type}, {"Prod5", Int64.Type}}),
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type", {"Cust_Name"}, "Attribute", "Value")
in
#"Unpivoted Other Columns"
如果您需要VBA解决方案,请测试下一个代码。它会在另一个sheet中return处理结果。它旨在处理 sheet(在 headers 行)中的产品数量。代码应该非常快,所有处理都在内存中完成:
Sub TransposeSummarize()
Dim sh As Worksheet, shRet As Worksheet, lastR As Long, lastCol As Long, dict As Object
Dim arr, arrFin, arrDict, i As Long, J As Long, k As Long, count As Long
Set sh = ActiveSheet
Set shRet = sh.Next 'use here the sheet you need returning
lastR = sh.Range("A" & sh.rows.count).End(xlUp).row 'last row
lastCol = sh.cells(1, sh.Columns.count).End(xlToLeft).Column 'last column
arr = sh.Range("A1", sh.cells(lastR, lastCol)).Value 'place the range in an array for faster iteration
ReDim arrDict(UBound(arr, 2) - 2) 'Redim the arrDict for first time
Set dict = CreateObject("Scripting.Dictionary") 'set the Dictionary (Scripting) object
For i = 2 To UBound(arr) 'iterate between the array elements (rows and columns)
For J = 2 To UBound(arr, 2)
arrDict(J - 2) = arr(i, J) 'fill arrDict with values on the i row
Next J
dict(arr(i, 1)) = arrDict 'place the array as dictionary item
Erase arrDict: ReDim arrDict(UBound(arr, 2) - 2) 'reinitialize the necessary array
Next i
ReDim arrFin(1 To dict.count * lastCol + 1, 1 To 3): k = 1
'Put the Headers in the final array:
arrFin(1, 1) = "Cust_Name": arrFin(1, 2) = "Product": arrFin(1, 3) = "Price": k = 2
For i = 0 To dict.count - 1 'process the dictionary keys/items and create the final array
arrFin(k, 1) = dict.Keys()(i)
For J = 0 To UBound(dict.Items()(i))
If dict.Items()(i)(J) <> 0 Then
arrFin(k, 2) = arr(1, J + 2): arrFin(k, 3) = dict.Items()(i)(J)
count = count + dict.Items()(i)(J): k = k + 1
End If
Next J
arrFin(k, 1) = "Total " & dict.Keys()(i): arrFin(k, 2) = "-": arrFin(k, 3) = count
count = 0: k = k + 1
Next i
'drop the array content at once, at the end of the code:
shRet.Range("A1").resize(k - 1, UBound(arrFin, 2)).Value = arrFin
End Sub
已编辑:
我把上面的代码复杂化了,只是因为我在收到关于唯一“cust_names”的答案之前就开始处理它了。我打算使用字典来处理多个这样的名字。下一个版本,不再使用字典,提取最后的数组内容只处理第一个。只是玩 VBA:
Sub TransposeSummarizeUnique()
Dim sh As Worksheet, shRet As Worksheet, lastR As Long, lastCol As Long
Dim arr, arrFin, i As Long, J As Long, k As Long, count As Long
Set sh = ActiveSheet
Set shRet = sh.Next 'use here the sheet you need returning
lastR = sh.Range("A" & sh.rows.count).End(xlUp).row 'last row
lastCol = sh.cells(1, sh.Columns.count).End(xlToLeft).Column 'last column
arr = sh.Range("A1", sh.cells(lastR, lastCol)).Value 'place the range in an array for faster iteration
ReDim arrFin(1 To UBound(arr) * lastCol + 1, 1 To 3)
'Put the Headers in the final array:
arrFin(1, 1) = "Cust_Name": arrFin(1, 2) = "Product": arrFin(1, 3) = "Price": k = 2
For i = 2 To UBound(arr) 'iterate between the array rows:
arrFin(k, 1) = arr(i, 1) 'fill the customer name
For J = 2 To UBound(arr, 2) 'iterate beteen the array columns"
If arr(i, J) <> 0 Then
arrFin(k, 2) = arr(1, J): arrFin(k, 3) = arr(i, J)'fill the product and its value
count = count + arr(i, J): k = k + 1 'calculate the values sum
End If
Next J
'write the balance row (Total, Sum):
arrFin(k, 1) = "Total " & arr(i, 1): arrFin(k, 2) = "-": arrFin(k, 3) = count
count = 0: k = k + 1 'reinitialize the count and increment the array row
Next i
'drop the array content at once, at the end of the code:
shRet.Range("A1").resize(k - 1, UBound(arrFin, 2)).Value = arrFin
End Sub
我在 excel 中有一些数据,格式如下:
Cust_Name Prod1 Prod2 Prod3 Prod4 Prod5
A 0 100 120 0 0
B 145 120 168 0 200
C 350 300 0 340 0
我需要将以下格式转换为below-mentioned报告格式。
我想通过 Cust_Name 转置列组中的那些产品,其值 >0 否则它不应成为最终输出报告的一部分。
我尝试了很多枢轴选项,但都没有用。
所需输出:
Cust_Name Product Price
A Prod2 100
Prod3 120
Total A - 220
B Prod1 145
Prod2 120
Prod3 168
Prod5 200
Total B - 633
C Prod1 350
Prod2 300
Prod4 340
Total C - 890
您可以使用 PowerQuery 执行此操作。
Select 源数据中的任何单元格。使用数据>获取并转换数据>来自 Table/Range.
PowerQuery 编辑器将打开,如下所示:
Select Cust_Name 列通过单击 header 列。使用转换>逆透视列>逆透视其他列:
此时,可选择过滤“值”列以排除 0。
现在使用“开始”>“关闭并加载”将数据放回您的工作簿。
您现在可以创建数据透视表 table 来获取小计:
这是 PowerQuery 编辑器中“高级编辑器”对话框的查询:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Cust_Name", type text}, {"Prod1", Int64.Type}, {"Prod2", Int64.Type}, {"Prod3", Int64.Type}, {"Prod4", Int64.Type}, {"Prod5", Int64.Type}}),
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type", {"Cust_Name"}, "Attribute", "Value")
in
#"Unpivoted Other Columns"
如果您需要VBA解决方案,请测试下一个代码。它会在另一个sheet中return处理结果。它旨在处理 sheet(在 headers 行)中的产品数量。代码应该非常快,所有处理都在内存中完成:
Sub TransposeSummarize()
Dim sh As Worksheet, shRet As Worksheet, lastR As Long, lastCol As Long, dict As Object
Dim arr, arrFin, arrDict, i As Long, J As Long, k As Long, count As Long
Set sh = ActiveSheet
Set shRet = sh.Next 'use here the sheet you need returning
lastR = sh.Range("A" & sh.rows.count).End(xlUp).row 'last row
lastCol = sh.cells(1, sh.Columns.count).End(xlToLeft).Column 'last column
arr = sh.Range("A1", sh.cells(lastR, lastCol)).Value 'place the range in an array for faster iteration
ReDim arrDict(UBound(arr, 2) - 2) 'Redim the arrDict for first time
Set dict = CreateObject("Scripting.Dictionary") 'set the Dictionary (Scripting) object
For i = 2 To UBound(arr) 'iterate between the array elements (rows and columns)
For J = 2 To UBound(arr, 2)
arrDict(J - 2) = arr(i, J) 'fill arrDict with values on the i row
Next J
dict(arr(i, 1)) = arrDict 'place the array as dictionary item
Erase arrDict: ReDim arrDict(UBound(arr, 2) - 2) 'reinitialize the necessary array
Next i
ReDim arrFin(1 To dict.count * lastCol + 1, 1 To 3): k = 1
'Put the Headers in the final array:
arrFin(1, 1) = "Cust_Name": arrFin(1, 2) = "Product": arrFin(1, 3) = "Price": k = 2
For i = 0 To dict.count - 1 'process the dictionary keys/items and create the final array
arrFin(k, 1) = dict.Keys()(i)
For J = 0 To UBound(dict.Items()(i))
If dict.Items()(i)(J) <> 0 Then
arrFin(k, 2) = arr(1, J + 2): arrFin(k, 3) = dict.Items()(i)(J)
count = count + dict.Items()(i)(J): k = k + 1
End If
Next J
arrFin(k, 1) = "Total " & dict.Keys()(i): arrFin(k, 2) = "-": arrFin(k, 3) = count
count = 0: k = k + 1
Next i
'drop the array content at once, at the end of the code:
shRet.Range("A1").resize(k - 1, UBound(arrFin, 2)).Value = arrFin
End Sub
已编辑:
我把上面的代码复杂化了,只是因为我在收到关于唯一“cust_names”的答案之前就开始处理它了。我打算使用字典来处理多个这样的名字。下一个版本,不再使用字典,提取最后的数组内容只处理第一个。只是玩 VBA:
Sub TransposeSummarizeUnique()
Dim sh As Worksheet, shRet As Worksheet, lastR As Long, lastCol As Long
Dim arr, arrFin, i As Long, J As Long, k As Long, count As Long
Set sh = ActiveSheet
Set shRet = sh.Next 'use here the sheet you need returning
lastR = sh.Range("A" & sh.rows.count).End(xlUp).row 'last row
lastCol = sh.cells(1, sh.Columns.count).End(xlToLeft).Column 'last column
arr = sh.Range("A1", sh.cells(lastR, lastCol)).Value 'place the range in an array for faster iteration
ReDim arrFin(1 To UBound(arr) * lastCol + 1, 1 To 3)
'Put the Headers in the final array:
arrFin(1, 1) = "Cust_Name": arrFin(1, 2) = "Product": arrFin(1, 3) = "Price": k = 2
For i = 2 To UBound(arr) 'iterate between the array rows:
arrFin(k, 1) = arr(i, 1) 'fill the customer name
For J = 2 To UBound(arr, 2) 'iterate beteen the array columns"
If arr(i, J) <> 0 Then
arrFin(k, 2) = arr(1, J): arrFin(k, 3) = arr(i, J)'fill the product and its value
count = count + arr(i, J): k = k + 1 'calculate the values sum
End If
Next J
'write the balance row (Total, Sum):
arrFin(k, 1) = "Total " & arr(i, 1): arrFin(k, 2) = "-": arrFin(k, 3) = count
count = 0: k = k + 1 'reinitialize the count and increment the array row
Next i
'drop the array content at once, at the end of the code:
shRet.Range("A1").resize(k - 1, UBound(arrFin, 2)).Value = arrFin
End Sub