【问题标题】:Excel VBA - transpose, copy and paste into different rows, with conditionsExcel VBA - 转置,复制和粘贴到不同的行,有条件
【发布时间】:2017-05-24 00:24:23
【问题描述】:

我对 Excel 中的 VBA 完全陌生。

我的数据由 G 列(包含奖牌列表)和 H 列(代表国家/地区)组成。我想转置我的 NOC,使 J 列代表金牌,其余为其他奖牌(只要它们在同一行,顺序无关紧要是银牌还是铜牌)。请参考我下面的图片,这对我想要做什么是不言自明的。

我尝试编写 VBA 代码,以便它将列向下复制三并转置,但有很多次它没有通过三。有时有两枚铜牌,有时没有铜牌。

我认为它的工作方式是读取 G 列并沿着该列向下查找 Gold,如果找到“Gold”,那么我希望它转置下一列 H 的值,直到下一个 Gold 是在 G 列中找到。

下面由红色箭头指示的附图是我想要做的。

非常感谢您的帮助。

what i want to do

== 我设法在 stackoverflow 的帮助下解决了我的问题,这就是结果。

Public Sub RunSQL()
    Dim conn As Object, rst As Object
    Dim strConnection As String, strSQL As String
    Dim i As Integer

    Set conn = CreateObject("ADODB.Connection")
    Set rst = CreateObject("ADODB.Recordset")

    ' CONNECTION STRING
    strConnection = "DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _
                  & "DBQ=C:\Path\To\Current\Workbook.xlsm;"
    ' SQL STATEMENT
    strSQL = "TRANSFORM MAX(m.NOC) AS CountryCode" _
        & " SELECT m.[Event], m.[Event Gender]" _
        & " FROM (SELECT t.[Event], t.[Event Gender], t.[Medal], t.NOC," _
        & "              (SELECT Count(*) FROM [MAIN$] sub" _
        & "               WHERE sub.[Event] = t.[Event]" _
        & "                 AND sub.[Event Gender] = t.[Event Gender]" _
        & "                 AND sub.[Medal] = t.[Medal]" _
        & "                 AND (IIF(sub.[Medal]='Gold', 1, IIF(sub.[Medal]='Silver', 2, 3)) <" _
        & "                      IIF(t.[Medal]='Gold', 1, IIF(t.[Medal]='Silver', 2, 3))" _
        & "                      OR sub.[NOC] <= t.[NOC])) AS rn" _
        & "       FROM [MAIN$] t) m" _
        & " GROUP BY m.[Event], m.[Event Gender]" _
        & " PIVOT m.[Medal] & m.[rn] IN" _
        & "       ('Gold1', 'Gold2', 'Gold3', 'Silver1', 'Silver2', 'Silver3'," _
        & "        'Bronze1', 'Bronze2', 'Bronze3')"

    ' OPEN DB CONN
    conn.Open strConnection
    rst.Open strSQL, conn

    ' COLUMN HEADERS
    For i = 1 To rst.Fields.Count
        Worksheets("RESULTS").Cells(1, i) = rst.Fields(i - 1).Name
    Next i        

    ' DATA ROWS
    Worksheets("RESULTS").Range("A2").CopyFromRecordset rst

    rst.Close: conn.Close    
End Sub

【问题讨论】:

  • 用括号绘制的指标列(即事件?)非常重要。定义这 2 或 3 个分组的 F 列或之前的列中有什么?
  • 这是每场比赛的事件。所以我的专栏是,A:奥运会年份,B:主办城市 C:体育(例如 Auqatics) D:纪律(例如游泳) E:赛事(例如 100m 仰泳) F:赛事性别。所以我想要得到的是一个名单,列出了哪个国家在每场比赛中获得了金银铜牌。 :)
  • 您使用的是 Excel for Windows 还是 Mac?
  • 亲爱的 Parfait,我正在使用 Excel 2013 for windows!
  • 亲爱的 Parfait,这是完整列的列表。(i.stack.imgur.com/KFC3I.jpg) 正如您所看到的,有些赛事有两枚铜牌,一个赛事总计多达 4 枚奖牌。尽管未在此列表中显示,但有些赛事只有一两枚奖牌(金牌、金牌和银牌)。我会很感激你的帮助!谢谢!!

标签: vba loops conditional-statements


【解决方案1】:

您可以通过算法来代替转置它:

'Find the last used row in a Column: column A in this example
Dim LastRow As Long
With ActiveSheet
    LastRow = .Cells(.Rows.Count, "G").End(xlUp).Row
End With
MsgBox LastRow

'http://www.rondebruin.nl/win/s9/win005.htm

dim start as long
dim finish as long

for medal = 2 to lastrow
   if thisworkbook.worksheets("worksheetname").cells(medal,7).value = "gold" then
    start = medal
         for next_medal = medal+1 to lastrow
            if thisworkbook.worksheets("worksheetname").cells(next_medal,7).value = "gold"
                finish = next_medal -1 'because it should not copy the next gold in the previous row of J
                medal = next_medal-1'because it starts looking for the next gold the next round at -1

                'copy/assign the cells you want to transpose:
                for transposing = start to finish
                thisworkbook.worksheets("worksheetname").cells(2+counter,10+transposing-start).value = thisworkbook.worksheets("worksheetname").cells(transposing,7).value 'writing the rest of the medals to the right of the first gold medal
                next transposing
                counter = counter + 1'ensuring the next row in J will be filled next time.
            end if
         next next_medal
     end if
next medal

我的vba正在编译,所以我没有验证就写了,希望你理解这个想法:)

【讨论】:

  • 谢谢 Maximilian brutus,我尝试了您的代码,并且我将复制/分配单元格部分(转置,7)中的单元格更改为(转置,8),因为我想打印奖牌而不是金牌,银,青铜本身。但是当我运行代码时,结果显示了一步一步的转换,而我想要的是每行 3-4 个国家的汇编(金-银-青铜或金-银-青铜-青铜获胜国家)和每组新的事件(在这种情况下,它由奖牌'gold'表示),我希望它在下面一行。
  • 我想我没有说清楚,所以这就是我的意思!谢谢一堆。 [链接](i.stack.imgur.com/KFC3I.jpg)
  • 优秀的海蒂,人们通常会发布他们最终的工作解决方案作为他们问题的答案,(或在他们最初的问题中进行编辑),以便将来遇到同样问题的人,因你的奋斗而有所帮助,让世界一点点的改善。
  • 感谢您的提示,我一定会这样做的。我是stackoverflow本身的新手,所以我并不担心。 :)
【解决方案2】:

考虑一个专门用于运行crosstab query 的SQL 解决方案。 Excel for Windows 可以使用 ADO 连接到 Jet/ACE SQL 引擎(.dll 文件)并查询当前工作簿。

以下假设数据位于名为 Main 的选项卡中(如果需要,可更改查询的 FROM 子句),结果输出在名为 Results 的空选项卡中:

Public Sub RunSQL()
    Dim conn As Object, rst As Object
    Dim strConnection As String, strSQL As String
    Dim i As Integer

    Set conn = CreateObject("ADODB.Connection")
    Set rst = CreateObject("ADODB.Recordset")

    ' CONNECTION STRING
    strConnection = "DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _
                      & "DBQ=C:\Path\To\Current\Workbook.xlsm;"
    ' SQL STATEMENT
    strSQL = "TRANSFORM MAX(m.NOC) AS CountryCode" _
            & " SELECT m.[Event], m.[Event Gender]" _
            & " FROM (SELECT t.[Event], t.[Event Gender], t.[Medal], t.NOC," _
            & "              (SELECT Count(*) FROM [MAIN$] sub" _
            & "               WHERE sub.[Event] = t.[Event]" _
            & "                 AND sub.[Event Gender] = t.[Event Gender]" _
            & "                 AND sub.[Medal] = t.[Medal]" _
            & "                 AND (IIF(sub.[Medal]='Gold', 1, IIF(sub.[Medal]='Silver', 2, 3)) <" _
            & "                      IIF(t.[Medal]='Gold', 1, IIF(t.[Medal]='Silver', 2, 3))" _
            & "                      OR sub.[NOC] <= t.[NOC])) AS rn" _
            & "       FROM [MAIN$] t) m" _
            & " GROUP BY m.[Event], m.[Event Gender]" _
            & " PIVOT m.[Medal] & m.[rn] IN" _
            & "       ('Gold1', 'Gold2', 'Gold3', 'Silver1', 'Silver2', 'Silver3'," _
            & "        'Bronze1', 'Bronze2', 'Bronze3')"

    ' OPEN DB CONN
    conn.Open strConnection
    rst.Open strSQL, conn

    ' COLUMN HEADERS
    For i = 1 To rst.Fields.Count
        Worksheets("RESULTS").Cells(1, i) = rst.Fields(i - 1).Name
    Next i        

    ' DATA ROWS
    Worksheets("RESULTS").Range("A2").CopyFromRecordset rst

    rst.Close: conn.Close    
End Sub

输入

输出

【讨论】:

  • 亲爱的冻糕,非常感谢!但是有一个问题。如果一项赛事共有四枚奖牌,例如一枚金牌、一枚银牌和两枚铜牌,则您的代码不会反映第四枚奖牌(第二枚铜牌)。它只计入第三枚奖牌。第四枚奖牌怎么也能体现出来?
  • 获得两枚银牌的人也是如此。(例如:总共三枚奖牌,但一枚金牌,两枚银牌)。对我来说,奖牌的类型(金、银、铜)根本不重要,因为我的数据只强调“奖牌获得者”的国籍,而不管他们的类型。只是我需要他们在同一行。就这样。再次感谢您!
  • 我设法用三枚奖牌解决了这个问题。非常感谢冻糕!你的帮助真的节省了我的时间。祝你有美好的一天!
  • 解决方案已更新,可考虑任意组合的多个奖牌。
  • 哦耶!谢谢!正如 Maximilian brutus III 上面评论的那样,我会将它包含在我的问题中,以便其他与我有同样问题的人会注意到它。非常感谢
猜你喜欢
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-26
  • 1970-01-01
相关资源
最近更新 更多