Excel: 如何转置 select 列并按重复值分组? (一维到二维 table)
Excel: How to transpose select columns and group by repeated values? (1D to 2D table)
我正在处理交易的数据转储,它不是出于任何目的以非常友好的格式从特定系统导出的。
Excel 中的数据目前由大约 700,000 行组成,而一旦组织正确,应该只包含大约 70,000 行,其中一个特定列的唯一值被转置到一些其他列中。
目前我正在使用下面这样的(简化的)示例;
Request_ID Status Field_Name Value
01000 Rejected Name John Smith
01000 Rejected Acc Number 123456
01000 Rejected Date 1/12/2015
01000 Rejected Enquiry Type Type 1
01000 Rejected Reason Reason 1
01001 Completed Name Jane Jones
01001 Completed Acc Number 123457
01001 Completed Date 1/12/2015
01001 Completed Enquiry Type Type 2
01001 Completed Reason Reason 2
前两列(Request_ID 和 Status)只是重复值以满足大量数据行与每个单独的请求有关。
Field_Name 列是特定列在每个唯一的行上重复相同的一组值 Request_ID - Value 列列出了与每个 Field_Name.
相关的相应值
我想将第 3 列和第 4 列(Field_Name 和 Value)转置为行以生成类似下面的内容:
Request_ID Status Name Acc Number Date Enquiry Type Reason
01000 Rejected John Smith 123456 1/12/2012 Type 1 Reason 1
01001 Completed Jane Jones 123457 1/12/2012 Type 2 Reason 2
如您所见,上面的第二个示例更符合逻辑并且冗余数据更少 - 此外还允许进行简单的过滤和分析。
因此,我的第一个调用点是尝试通过将数据插入数据透视表来实现上述操作,但是我似乎无法理解其中的逻辑。或者,如果我能够将字段放入类似的列位置,那么这些值将简单地计算 table 正文中的计数,而不是值本身(数据透视表的性质)。
是否可以使用Transpose功能? (如果是这样,我很乐意自己调查)
有没有我没有考虑过的替代解决方案?
(旁注 - 我的数据转储中还有其他列,我没有包含在示例中,因为它们包含的值对与个人相关的每一行简单重复Request_ID - 所以我想我可以对上面适用的任何解决方案使用相同的逻辑)
如果您能指出正确的方向或提供任何指导,我将不胜感激,因为我很困惑。
假设您的数据在 A:D 列中。将列 Request_ID 复制到 Col G。使用 excel Remove Duplicates 函数获取唯一的请求 ID。从 Col H 开始为所有可能的字段名称(如名称、帐户编号等)制作 headers,并使用以下公式。
H2 =VLOOKUP(G2,$A:$D,2,FALSE)
I2 =INDIRECT(ADDRESS(SUMPRODUCT(--($A:$A=$G2)*--($C:$C=I)*ROW($A:$A)),4))
为所有其他字段名称拖动 I2 公式。
这是一个Google Sheet
我已经尝试使用您发布的数据并且工作正常。如果您想将整个过程自动化,您可以尝试为所有这些步骤录制宏。
选择任何单元格,说 G6 并输入:
=INDEX(A:A,(ROWS(:1)-1)*5+2)
然后抄下来。在H6中输入:
=INDEX(B:B,(ROWS(:1)-1)*5+2)
然后抄下来。最后在I6中输入:
=OFFSET($D,COLUMNS($A:A)-1+(ROWS(:1)-1)*5,0)
并上下复制此单元格:
SQL中条件聚合查询的经典需求。您的初始示例反映了 Entity-Attribute-Value 模型。要正确对齐不同的列,在 Field_Name 列上有条件地聚合,returning Value[=54 的最大值(唯一值) =],按重复列分组(添加到所有其他重复列的 SELECT
和 GROUP BY
):
条件聚合查询
SELECT Request_ID, Status,
MAX(IIF(Field_Name='Name', Value, NULL)) AS Name,
MAX(IIF(Field_Name='Acc Number', Value, NULL)) AS [Acc Number],
MAX(IIF(Field_Name='Date', Value, NULL)) AS [Date],
MAX(IIF(Field_Name='Enquiry Type', Value, NULL)) AS [Enquiry Type]
MAX(IIF(Field_Name='Reason', Value, NULL)) AS [Reason]
FROM [Worksheet$]
GROUP BY Request_ID, Status
如果在 PC 上使用 Excel,您可以使用 ACE SQL 引擎(Windows .dll 文件)运行 SQL 查询VBA 中的工作簿。如果使用 Mac,将数据导入数据库,如 SQLite 和 运行 上面的查询(将 IIF()
替换为 CASE
语句)。对于超过 700,000 条记录,与内联公式或嵌套 for
循环和数组相比,SQL 可能是一个可靠的解决方案。
下面是使用 ADO 的 Windows 解决方案(两个可用连接),其中数据驻留在 DATA 选项卡中,其中包含空白 RESULTS 用于查询结果的选项卡。
Sub RunSQL()
Dim conn As Object, rst As Object
Dim strConnection As String, strSQL As String, i As Integer
Set conn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
' CONNECTION STRINGS (DRIVER AND PROVIDER)
' strConnection = "DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _
' & ActiveWorkbook.FullName ";"
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" _
& "Data Source='" & ActiveWorkbook.FullName & "';" _
& "Extended Properties=""Excel 8.0;HDR=YES;"";"
strSQL = " SELECT Request_ID, Status," _
& " MAX(IIF(Field_Name='Name', Value, NULL)) AS Name," _
& " MAX(IIF(Field_Name='Acc Number', Value, NULL)) AS [Acc Number]," _
& " MAX(IIF(Field_Name='Date', Value, NULL)) AS [Date]," _
& " MAX(IIF(Field_Name='Enquiry Type', Value, NULL)) AS [Enquiry Type]," _
& " MAX(IIF(Field_Name='Reason', Value, NULL)) AS [Reason]" _
& " FROM [DATA$]" _
& " GROUP BY Request_ID, Status;"
' OPEN CONNECTION AND RECORDSET
conn.Open strConnection
rst.Open strSQL, conn
' HEADERS
For i = 0 To rst.Fields.Count - 1
Worksheets("RESULTS").Cells(1, i + 1) = rst.Fields(i).Name
Next i
' DATA ROWS
Worksheets("RESULTS").Range("A2").CopyFromRecordset rst
rst.Close: conn.Close
End Sub
或者,对于可变数量的 Field_Name
,您可以使用 ACE SQL 的唯一 crosstab query,它避免了硬编码值的可能性,例如上述聚合中的条件。并且因为 ACE SQL 将列限制为 255,下面的查询只能 return 253 个或更少 Field_Name
的不同值(对于重复的 groupby 列为 2):
交叉表查询
strSQL = " TRANSFORM Max(Value)" _
& " SELECT Request_ID, Status" _
& " FROM [DATA$]" _
& " GROUP BY Request_ID, Status" _
& " PIVOT Field_Name;"
数据
结果
根据您的 Excel 版本,您可以使用 Power Pivot
(2010/2013) 或 Get & Transform
(2016) 适当地转换数据。您的数据(如果尚未在 table 中)将转换为一个。
对于后者,Selecting From Table
打开查询编辑器。在 select 字段名称和值列之后,select Transform
► Pivot Column
这将打开一个“数据透视列”对话框。您要确保 select 离子如下所示。此外,您必须 select advanced
才能进入 do not aggregate
选项。
Select 好的,你得到了你问题中的结果。当您保存查询时,它会将结果写入新的工作表。您需要正确设置日期列的格式。
我不确定这将如何处理 700,000 行。您可能需要 64 位 Excel.
但是,查看对其他回复的一些评论,此解决方案应该适用于不同数量的 Field Name / Value
对。
我正在处理交易的数据转储,它不是出于任何目的以非常友好的格式从特定系统导出的。
Excel 中的数据目前由大约 700,000 行组成,而一旦组织正确,应该只包含大约 70,000 行,其中一个特定列的唯一值被转置到一些其他列中。
目前我正在使用下面这样的(简化的)示例;
Request_ID Status Field_Name Value
01000 Rejected Name John Smith
01000 Rejected Acc Number 123456
01000 Rejected Date 1/12/2015
01000 Rejected Enquiry Type Type 1
01000 Rejected Reason Reason 1
01001 Completed Name Jane Jones
01001 Completed Acc Number 123457
01001 Completed Date 1/12/2015
01001 Completed Enquiry Type Type 2
01001 Completed Reason Reason 2
前两列(Request_ID 和 Status)只是重复值以满足大量数据行与每个单独的请求有关。
Field_Name 列是特定列在每个唯一的行上重复相同的一组值 Request_ID - Value 列列出了与每个 Field_Name.
相关的相应值我想将第 3 列和第 4 列(Field_Name 和 Value)转置为行以生成类似下面的内容:
Request_ID Status Name Acc Number Date Enquiry Type Reason
01000 Rejected John Smith 123456 1/12/2012 Type 1 Reason 1
01001 Completed Jane Jones 123457 1/12/2012 Type 2 Reason 2
如您所见,上面的第二个示例更符合逻辑并且冗余数据更少 - 此外还允许进行简单的过滤和分析。
因此,我的第一个调用点是尝试通过将数据插入数据透视表来实现上述操作,但是我似乎无法理解其中的逻辑。或者,如果我能够将字段放入类似的列位置,那么这些值将简单地计算 table 正文中的计数,而不是值本身(数据透视表的性质)。
是否可以使用Transpose功能? (如果是这样,我很乐意自己调查)
有没有我没有考虑过的替代解决方案?
(旁注 - 我的数据转储中还有其他列,我没有包含在示例中,因为它们包含的值对与个人相关的每一行简单重复Request_ID - 所以我想我可以对上面适用的任何解决方案使用相同的逻辑)
如果您能指出正确的方向或提供任何指导,我将不胜感激,因为我很困惑。
假设您的数据在 A:D 列中。将列 Request_ID 复制到 Col G。使用 excel Remove Duplicates 函数获取唯一的请求 ID。从 Col H 开始为所有可能的字段名称(如名称、帐户编号等)制作 headers,并使用以下公式。
H2 =VLOOKUP(G2,$A:$D,2,FALSE)
I2 =INDIRECT(ADDRESS(SUMPRODUCT(--($A:$A=$G2)*--($C:$C=I)*ROW($A:$A)),4))
为所有其他字段名称拖动 I2 公式。
这是一个Google Sheet
我已经尝试使用您发布的数据并且工作正常。如果您想将整个过程自动化,您可以尝试为所有这些步骤录制宏。
选择任何单元格,说 G6 并输入:
=INDEX(A:A,(ROWS(:1)-1)*5+2)
然后抄下来。在H6中输入:
=INDEX(B:B,(ROWS(:1)-1)*5+2)
然后抄下来。最后在I6中输入:
=OFFSET($D,COLUMNS($A:A)-1+(ROWS(:1)-1)*5,0)
并上下复制此单元格:
SQL中条件聚合查询的经典需求。您的初始示例反映了 Entity-Attribute-Value 模型。要正确对齐不同的列,在 Field_Name 列上有条件地聚合,returning Value[=54 的最大值(唯一值) =],按重复列分组(添加到所有其他重复列的 SELECT
和 GROUP BY
):
条件聚合查询
SELECT Request_ID, Status,
MAX(IIF(Field_Name='Name', Value, NULL)) AS Name,
MAX(IIF(Field_Name='Acc Number', Value, NULL)) AS [Acc Number],
MAX(IIF(Field_Name='Date', Value, NULL)) AS [Date],
MAX(IIF(Field_Name='Enquiry Type', Value, NULL)) AS [Enquiry Type]
MAX(IIF(Field_Name='Reason', Value, NULL)) AS [Reason]
FROM [Worksheet$]
GROUP BY Request_ID, Status
如果在 PC 上使用 Excel,您可以使用 ACE SQL 引擎(Windows .dll 文件)运行 SQL 查询VBA 中的工作簿。如果使用 Mac,将数据导入数据库,如 SQLite 和 运行 上面的查询(将 IIF()
替换为 CASE
语句)。对于超过 700,000 条记录,与内联公式或嵌套 for
循环和数组相比,SQL 可能是一个可靠的解决方案。
下面是使用 ADO 的 Windows 解决方案(两个可用连接),其中数据驻留在 DATA 选项卡中,其中包含空白 RESULTS 用于查询结果的选项卡。
Sub RunSQL()
Dim conn As Object, rst As Object
Dim strConnection As String, strSQL As String, i As Integer
Set conn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
' CONNECTION STRINGS (DRIVER AND PROVIDER)
' strConnection = "DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _
' & ActiveWorkbook.FullName ";"
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" _
& "Data Source='" & ActiveWorkbook.FullName & "';" _
& "Extended Properties=""Excel 8.0;HDR=YES;"";"
strSQL = " SELECT Request_ID, Status," _
& " MAX(IIF(Field_Name='Name', Value, NULL)) AS Name," _
& " MAX(IIF(Field_Name='Acc Number', Value, NULL)) AS [Acc Number]," _
& " MAX(IIF(Field_Name='Date', Value, NULL)) AS [Date]," _
& " MAX(IIF(Field_Name='Enquiry Type', Value, NULL)) AS [Enquiry Type]," _
& " MAX(IIF(Field_Name='Reason', Value, NULL)) AS [Reason]" _
& " FROM [DATA$]" _
& " GROUP BY Request_ID, Status;"
' OPEN CONNECTION AND RECORDSET
conn.Open strConnection
rst.Open strSQL, conn
' HEADERS
For i = 0 To rst.Fields.Count - 1
Worksheets("RESULTS").Cells(1, i + 1) = rst.Fields(i).Name
Next i
' DATA ROWS
Worksheets("RESULTS").Range("A2").CopyFromRecordset rst
rst.Close: conn.Close
End Sub
或者,对于可变数量的 Field_Name
,您可以使用 ACE SQL 的唯一 crosstab query,它避免了硬编码值的可能性,例如上述聚合中的条件。并且因为 ACE SQL 将列限制为 255,下面的查询只能 return 253 个或更少 Field_Name
的不同值(对于重复的 groupby 列为 2):
交叉表查询
strSQL = " TRANSFORM Max(Value)" _
& " SELECT Request_ID, Status" _
& " FROM [DATA$]" _
& " GROUP BY Request_ID, Status" _
& " PIVOT Field_Name;"
数据
结果
根据您的 Excel 版本,您可以使用 Power Pivot
(2010/2013) 或 Get & Transform
(2016) 适当地转换数据。您的数据(如果尚未在 table 中)将转换为一个。
对于后者,Selecting From Table
打开查询编辑器。在 select 字段名称和值列之后,select Transform
► Pivot Column
这将打开一个“数据透视列”对话框。您要确保 select 离子如下所示。此外,您必须 select advanced
才能进入 do not aggregate
选项。
Select 好的,你得到了你问题中的结果。当您保存查询时,它会将结果写入新的工作表。您需要正确设置日期列的格式。
我不确定这将如何处理 700,000 行。您可能需要 64 位 Excel.
但是,查看对其他回复的一些评论,此解决方案应该适用于不同数量的 Field Name / Value
对。