是否有快速的方式来解决问题" Excel矩阵/数据透视表(在Excel或其他地方),无需编写宏或其他代码?
同样,我可以编写自己做的代码(C#或VBA或其他)。
我想知道是否可以快速执行没有代码?
E.g。我需要转换此权限矩阵(以Excel表格/矩阵形式给出)
进入这个半规范化的表(所以我可以将它插入到SQL数据库中):
e.g。在SQL中,我可以这样做:
CREATE TABLE dbo.T_DocumentMatrix
(
[Function] [varchar](255) NULL,
[GROUP-Admin] [varchar](255) NULL,
[GROUP-SuperUser] [varchar](255) NULL,
[GROUP-Manager] [varchar](255) NULL,
[GROUP-OLAP] [varchar](255) NULL,
[GROUP-1] [varchar](255) NULL,
[GROUP-2] [varchar](255) NULL,
[GROUP-3] [varchar](255) NULL,
[GROUP-4] [varchar](255) NULL,
[GROUP-5] [varchar](255) NULL,
[GROUP-6] [varchar](255) NULL,
[GROUP-7] [varchar](255) NULL,
[GROUP-8] [varchar](255) NULL,
[Externals] [varchar](255) NULL
);
从excel复制粘贴数据,然后
SELECT *
FROM
(
SELECT
[Function]
,[GROUP-Admin]
,[GROUP-SuperUser]
,[GROUP-Manager]
,[GROUP-OLAP]
,[GROUP-1]
,[GROUP-2]
,[GROUP-3]
,[GROUP-4]
,[GROUP-5]
,[GROUP-6]
,[GROUP-7]
,[GROUP-8]
,[Externals]
FROM T_DocumentMatrix
) AS p
UNPIVOT
(
Rights FOR GroupName IN
(
[GROUP-Admin]
,[GROUP-SuperUser]
,[GROUP-Manager]
,[GROUP-OLAP]
,[GROUP-1]
,[GROUP-2]
,[GROUP-3]
,[GROUP-4]
,[GROUP-5]
,[GROUP-6]
,[GROUP-7]
,[GROUP-8]
,[Externals]
)
) AS unpvt
;
但是,这需要我为组中的每个更改更改表创建脚本和unpivot脚本...
答案 0 :(得分:4)
哦,好吧,这有点复杂。 其中一个问题是,向导调用快捷方式在非英语版本的excel中不起作用(该死的,在家我会有英文版,但在这里工作......)
这是一个很好的视频: https://www.youtube.com/watch?v=pUXJLzqlEPk
但是可以删除YouTube视频,以便使其成为可靠的答案:
首先,您需要转到“选项”,然后添加menuband-item“Pivot table and PivotChart Wizard”。
然后删除行和列字段
双击NUMBER(图中的54)
和excel将为您提供中途标准化数据。
答案 1 :(得分:1)
虽然这是一个非常古老的问题,而且 Stefan 在当天找到了一个开明的答案,但值得重新审视。我自己就遇到了对这种无代码、动态 Unpivot 方法的需求,谷歌搜索将我带到了这里。是的,Power Query 可以完成这项工作,但这并不是完全无代码的,因为在 Power BI 中运行了一个脚本化的后台解决方案,它需要用户刷新数据(因此,它在工作簿中不是自动的)并且它不会在 Excel for Mac (tmk) 上运行。
以下是基于动态数组并使用 LET 函数的方法,因此需要 Excel 2016 或 Microsoft 365。
假设 Stefan 的数据位于单元格 A1 到 N8 中。在 Power Query 中,我们会说 Stefan 想要“Unpivot B1:N8 By A1:A8”。
<块引用>注意:以下方法也可以接受 By 的多个列,例如您可能需要“逆透视 D1:N8 通过 A1:C8”。
=LET( unPivMatrix, B1:N8,
byMatrix, A1:A8,
upC, COLUMNS( unPivMatrix ),
byC, COLUMNS( byMatrix ),
dmxR, MIN( ROWS( unPivMatrix ), ROWS( byMatrix ) ) - 1,
upCells, dmxR * upC,
upSeq, SEQUENCE( upCells,, 0 ),
upHdr, INDEX( INDEX( unPivMatrix, 1, ), 1, SEQUENCE( upC ) ),
upBody, INDEX( unPivMatrix, SEQUENCE( dmxR ) + 1, SEQUENCE( 1, upC ) ),
byBody, INDEX( byMatrix, SEQUENCE( dmxR ) + 1, SEQUENCE( 1, byC ) ),
attr, INDEX( upHdr, MOD( upSeq, upC ) + 1 ),
mux, INDEX( upBody, upSeq/upC + 1, MOD( upSeq, upC ) + 1 ),
demux, IFERROR( INDEX(
IFERROR( INDEX( byBody,
IFERROR( INT( SEQUENCE( upCells, byC,0 )/byC/upC ) + 1, MOD( upSeq, upC ) + 1 ),
SEQUENCE( 1, byC + 1 ) ),
attr ),
upSeq + 1, SEQUENCE( 1, byC + 2 ) ),
mux ),
demux
)
工作原理 - 读取输入
输入是您要取消旋转的范围,我称之为 unPivMatrix B1:N8(可以是您需要的任何维度)以及您要取消旋转的列,我称之为byMatrix A1:A8。
<块引用>通常,byMatrix 的行需要与 unPivMatrix 相同,因此您必须从 A1 开始而不是 A2。我决定采取 这个约定,因为它们可能是 A1 中的标题,并且有一些 小模组,这个公式可以产生与 Power Query,但这不是 Stefan 要求的。
该公式首先计算每个矩阵中的列数:upC 反透视列和 byC 列。从这些它计算 dmxR(多路分解行):通过取 unPivMatrix 和 byMatrix 的行中的最小值并减去 1,因为 unPivMatrix 有一个标题,将在 unpivot 中传递多少行值。如果输入具有不同的行数(根据定义,这是错误的),则采用 MIN 是一个错误预防步骤。
这些值用于创建稍后将用于形成输出的整形变量。 upCells 是将被取消旋转的值的数量,用于生成名为 upSeq 的索引模式,该模式从 0 开始计算将在 INDEX 中使用的值的数量稍后发挥作用。我们从 0 开始,因为 upSeq 将被调制以形成输入和输出的正确索引。
现在我们将分解矩阵的各个部分,以便我们可以对它们进行多路复用。部分看起来像这样:
有一个 unpivot 标头 (upHdr),其中包含值数据的标识符(在 Stefan 的例子中,GROUP-Admin、GROUP-SuperUser 等)。这些将被多路复用到一个列中,该列稍后将放置在每个未旋转的值旁边。 upHdr 是通过将整个 unPivMatrix 放入一个 INDEX 函数并读取第 1 行和所有列来创建的。我将该 INDEX 函数嵌套到另一个 INDEX 中,该 INDEX 使用大小为 upC 的垂直序列将水平数组重塑为垂直数组。
upBody 包含我们要通过多路复用反透视的值。它是通过将 upMatrix 放入一个 INDEX 并通过将输出 SEQUENCE( dmxR ) + 1 § 针对要读取的每一列 SEQUENCE( upC ) 的行数对其进行整形来创建的。 byBody 包含将针对 upBody 中的每个值进行多路复用的数据。它的创建方式与 upBody 相同。
§ - 添加 1 以跳过标题行
工作原理 - 塑造和编写输出
输出将是这样的:
我们现在将 upHdr 多路复用为 attr 或属性(使用 Power Query 术语),方法是将 upHdr 放入 INDEX 并应用基于 upSeq 的调制序列,该序列重复每 upC 次(例如 {{1} })。 注意:这就是 upSeq 中从 0 开始很重要的地方。 attr 的输出看起来像(在 Stefan 的情况下){1;2;3;4;5;6;7;8;1;2;...}
。
mux 是将针对每个属性和 byBody 行进行多路复用的值(使用 Power Query 术语)。它是通过将 valBody 放入 INDEX 然后将其整形为由行创建的多路复用模式来创建的
{GROUP-Admin; GROUP-SuperUser, etc.}
产生一行 upSeq/upC + 1
和
的列{1,1,1,1,1,1,1,1,2,2,...}
+ 1 产生一列 MOD( upSeq, upC )
。
mux 的输出将是 unPivMatrix 的内容。在 Stefan 的情况下,这会有点特殊,因为他使用 * 和空白作为数据。此公式会将空格转换为 0。因此,如果这是一个问题,您可以将多路复用器包装到 {1;2;3;4;5;6;7;8;1;...}
中,但我不会添加它,因为我想要一个通用的逆向旋转,因为我确信 Stefan 早就开始了。
工作原理 - 将部分解复用到输出中
现在简单的部分已经完成,是时候处理困难的部分了——将所有这些整合到一个动态数组中。将多个数组放在一起需要一个技巧,这个技巧必须应用两次,因为如您所见,我们将三个表放在一起。诀窍就像有一个 APPEND 函数,如:
IF( ISBLANK( mux ), "", mux )
。
要合并两个数组,请将第一个数组放入 INDEX,然后引用数组外部的单元格以强制执行 #REF!错误。例如,如果我有一个 3 x 2 的字母 A 到 F 数组,并且我引用了单元格 3、3,它将抛出引用错误。
现在,您可以通过将 INDEX 包装在 IFERROR 中来将错误替换为要附加的表来利用这些错误。有点像:
APPEND( APPEND( table1, table2 ), table3 )
从这个意义上说,上面的公式等效于 APPEND( table1, table2 ),其中 APPEND 是我们想要的两个表的逐行追加。 (注意:切换序列模式,您可以按列进行追加。)
所以,希望这个解释可以清楚地说明在一个名为 demux 的变量的最后阶段发生了什么,它提供了结果。我为结果命名,然后引用它,以便您可以轻松探索、修改或优化公式。所以,demux 真的很像:
IFERROR( INDEX( table1,
SEQUENCE( table1.rows ),
SEQUENCE( 1, table1.columns + table2.columns ) ),
table2 )
我不会深入讨论这个最后阶段的工作原理,因为这已经是一个很长的答案,但简短的总结是这个附加使用由 upCells、upC 和 byC 创建的维度来形成输出。
我已经对此进行了测试,但我没有对其进行性能优化或使其达到#SwissEngineering 标准。
答案 2 :(得分:0)
现在有另一种方法可以通过Power Query:
Data
> From a table or a range
screenshot Transform
> Unpivot
screenshot Home
> Close and load
screenshot Refresh
(如果原始表已更新screenshot 答案 3 :(得分:0)
我正在使用此VBA代码
Sub Unpivot()
'
Dim Rowlabel As Range
Dim Columnlabel As Range
Dim Pap As Range
Dim Tabl As Range
Dim i As Integer
Dim j As Integer
Dim a As Integer
Dim b As Integer
Dim Data As Range
Dim k As Integer
Dim Label As Range
Dim pvtCache As PivotCache
Dim pvt As PivotTable
Dim SrcData As String
'
ActiveSheet.Copy Before:=Worksheets(1)
Set Tabl = Selection
For Each Pap In Tabl
If Pap.MergeCells Then
With Pap.MergeArea
.UnMerge
.Value = Pap.Value
End With
End If
Next
i = Application.InputBox("Number of row contain label:", "Excel", i, Type:=2)
j = Application.InputBox("Number of column contain label:", "Excel", j, Type:=2)
On Error Resume Next
Sheets("Unpivot_Table").Delete
Sheets.Add.Name = "Unpivot_Table"
Set Pap = Range("Unpivot_Table!B2")
b = Tabl.Rows.Count
a = Tabl.Columns.Count
Set Data = Range(Tabl.Cells(i + 1, j + 1), Tabl.Cells(b, a))
Set Columnlabel = Range(Tabl.Cells(i + 1, 1), Tabl.Cells(b, j))
Set Rowlabel = Range(Tabl.Cells(1, j + 1), Tabl.Cells(i, a))
Pap.Select
For Each Column In Data.Columns
Column.Copy
Selection.PasteSpecial Paste:=xlPasteValues
Columnlabel.Copy
Selection.Offset(0, 1).PasteSpecial Paste:=xlPasteValues
Column.Copy
Selection.Offset(b - i, -1).Select
Next Column
Pap.Offset(0, j + 1).Select
For Each Column In Rowlabel.Columns
Column.Copy
Range(Selection, Selection.Offset(b - i - 1, 0)).PasteSpecial Paste:=xlPasteValues, Transpose:=True
Selection.End(xlDown).Offset(1, 0).Select
Next Column
Set Label = Range(Pap.Offset(-1, 0), Pap.Offset(0, i + j + 1))
For k = 1 To i + j + 1
Label.Cells(1, k).Value = Application.InputBox(Label.Cells(2, k).Value & " is belong to Fieldname", "Hoang", k, Type:=2)
Next
Range(Pap.End(xlUp), Pap.End(xlDown).End(xlToRight)).Select
SrcData = ActiveSheet.Name & "!" & Selection.Address
On Error Resume Next
Sheets("Pivot").Delete
Sheets.Add.Name = "Pivot"
Set pvtCache = ActiveWorkbook.PivotCaches.Create( _
SourceType:=xlDatabase, _
SourceData:=SrcData)
Set pvt = pvtCache.CreatePivotTable( _
TableDestination:="Pivot!" & Sheets("Pivot").Range("A3").Address(ReferenceStyle:=xlR1C1), _
TableName:="PivotTable1")
End Sub
答案 4 :(得分:0)
我相信您可以使用以下一种模块化算术。使用cols和row图例将数据放入此UDF的参数中。
Function MyUnpivot(matice As Range) As Variant
Dim I As Integer
Dim J As Integer
Dim radka As Integer
Dim sloupec As Integer
I = matice.Rows.Count - 1
J = matice.Columns.Count - 1
Dim returnVal()
ReDim Preserve returnVal(1 To I * J, 1 To 3)
For x = 1 To I * J
radka = ((x - 1) Mod I) + 2
sloupec = WorksheetFunction.Floor_Math((x - 1 / 2) / I) + 2
returnVal(x, 1) = matice.Cells(1, sloupec)
returnVal(x, 2) = matice.Cells(radka, 1)
returnVal(x, 3) = matice.Cells(radka, sloupec)
Next
MyUnpivot = returnVal
End Function