使用 SQL 查询的 UNPIVOT 列

UNPIVOT columns using SQL query

我正在提取另一个包含 table 的工作簿,其中包含像 ItemCreationDate 这样的列,并且大多数列(总共 28 个这样的列)以单词 "Global" 开头。我想

  1. 将这些 "Global" 列(包括 ItemCreationDate)拉入 SQL 记录集中, 添加一个名为 Old/New 的新列,然后添加
  2. UNPIVOT 它们,即将它们一层层堆叠起来
  3. 在下一列中,列出他们的列项目及其计数。
  4. 它们的计数是基于 ItemCreationDate 得出的,其中 <2015 年的任何日期都是旧的,>=2015 年的是新的
  5. 最终输出应如输出 sheet 所示。

我附上了一个 Sample.xlsx 文件,我在其中展示了我必须如何从数据 sheet 开始到达“输出”选项卡。此数据 sheet 实际上是我想要拉入记录集并吐出 table 的输入,如输出 sheet 所示。我不想创建 Pivot table,因为它很麻烦而且数据很多,我想要另一种 SQL 方法,其中我可以快速聚合数据并将其插入 sheet 一气呵成。

我没有使用 SQL 服务器,因此无法使用 UNPIVOT 命令或动态 SQL 遍历所有 "Global" 列。

基本上我想形成一个正确的 SQL 字符串,例如....

Dim arrSQL as variant
......
......
RS.Filter="Like Global*"
......
arrSQL = JOIN(RS.Fields, vbCr)

strSQL = "SELECT [arrSQL], IIF(YEAR([ITEM CREATION DATE])>=YEAR(DATE())-1,""NEW"",""OLD"") AS [New/Old]  from [Data$] GROUP BY...."
strSQL = strSQL & " UNION ALL " & vbcr & _
strSQL = strSQL & " ......

现在,运行 SQL 在同一记录集上减少列并获得所需的数据格式.... 我知道上面的内容不太正确,但在这些行上有一些内容,以便我可以获得正确的输出,如“输出”选项卡中所示。

谁能帮忙快点?

@a_horse_with_no_name 的编辑:

查看示例文件的截图:

  1. 数据sheet: 这实际上是我想拉入 Recordset 的输入工作簿中的 table。查看各种 "Global" 列标题及其我想要取消透视的项目。

  1. 这是我每次都必须创建的 2 个中间 sheets "New" 和 "Old"(实际上我想摆脱)。在 2015 年或之后找到的任何项目都放在新的,而其余的放在旧的。

  1. 仅供参考,在输出列中手动使用的公式是:

C 列(新):

=COUNTIF(INDEX(New!$A:$D,0,MATCH($A2,New!:,0)),Output!$B2)

D 列(旧):

=COUNTIF(INDEX(Old!$A:$D,0,MATCH($A2,Old!:,0)),Output!$B2)

E 列(新增百分比):

=Output!C2/SUM(C:C)

F 列(旧百分比):

=Output!D2/SUM(D:D)

G 列(索引):

=IF(AND(E2<=0,F2<=0),0,IF(AND(E2>0,F2>0),E2/F2,1))

希望对您有所帮助。

事实上,您可以 运行 SQL 使用 Jet/ACE SQL Engine(一个 Windows .dll 文件)在 MS Excel 中查询,这正是数据MS Access 默认连接的商店。因此,所有 PC 上配备的这项技术并不局限于任何一个 Office/Windows 程序。

考虑以下 Excel VBA 宏(如果在 PC 上使用 Excel),它通过 ADO 运行 连接到 ACE 三个聚合 SQL 查询(GLOBAL VIT/CALCGLOBAL FLAVOURSGLOBAL FLAVOR GROUP)和条件查询新旧counts/percentages。后一个百分比列对需要子查询。

要正确设置,请执行以下操作:

  1. 确保 Item Creation Date 是 MM-DD-YYYY (US-based) 或 DD-MM-YYYY(基于 non-US)的日期格式上面的屏幕截图或文件如何具有当前格式的日期字段。

    Sub FormatDates() For i = 2 To 2083 Range("A" & i) = CDate(Range("A" & i)) Next i End Sub

  2. 运行 宏位于与保存数据的工作簿不同的工作簿中。下面假设数据工作簿在名为 Data.

  3. 的工作表中保存源信息
  4. 在 query-running 工作簿中,创建一个名为 RESULTS 的空白工作表,其中将填充包含列 headers.
  5. 的查询输出

VBA 脚本 (两个连接可用 Driver(注释掉)和提供商版本)

Option Explicit

Sub RunSQL()
    Dim cols As Object, datawbk As Workbook, datawks As Worksheet
    Dim lastcol As Integer, i As Integer, j As Variant, output As Variant

    Set cols = CreateObject("Scripting.Dictionary")
    Set datawbk = Workbooks.Open("C:\Path\To\Data\Workbook.xlsx;")
    Set datawks = datawbk.Worksheets("Data")
    lastcol = datawks.Cells(7, datawks.Columns.Count).End(xlToLeft).Column

    For i = 2 To lastcol
         cols.Add CStr(i - 1), datawks.Cells(1, i).Value
    Next i

    datawbk.Close False
    Set datawks = Nothing
    Set datawbk = Nothing

    output = DataCapture(cols)

End Sub

Function DataCapture(datacols As Object)
On Error GoTo ErrHandle
    Dim conn As Object, rst As Object
    Dim strConnection As String
    Dim classSQL As String, itemSQL As String, grpSQL As String, strSQL As String
    Dim i As Integer, fld As Object, d As Variant, lastrow As Integer

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

    ' Hard code database location and name '
'    strConnection = "DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _
'                      & "DBQ=C:\Path\To\Data\Workbook.xlsx;"
    strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" _
                       & "Data Source='C:\Path\To\Data\Workbook.xlsx;" _
                       & "Extended Properties=""Excel 12.0 XML;HDR=YES IMEX=1;"";"

    ' OPEN DB CONNECTION '
    conn.Open strConnection

    For Each d In datacols.keys
        strSQL = " SELECT '" & datacols(d) & "' AS [COLUMN], [Data$].[" & datacols(d) & "] AS ITEMS," _
                    & "   SUM(IIF(Year([Item Creation Date]) >= Year(Date()) - 1, 1, 0)) AS NEW," _
                    & " " _
                    & "   SUM(IIF(Year([Item Creation Date]) < Year(Date()) - 1, 1, 0)) AS OLD," _
                    & " " _
                    & "   ROUND(SUM(IIF(Year([Item Creation Date]) >= Year(Date()) - 1, 1, 0)) / " _
                    & "   (SELECT Count(*) FROM [Data$] AS sub" _
                    & "    WHERE Year(sub.[Item Creation Date]) >= Year(Date()) - 1),2) AS NEWPCT," _
                    & " " _
                    & "   ROUND(SUM(IIF(Year([Item Creation Date]) < Year(Date()) - 1, 1, 0)) / " _
                    & "   (SELECT Count(*) FROM [Data$] AS sub" _
                    & "    WHERE Year(sub.[Item Creation Date]) < Year(Date()) - 1),2) AS OLDPCT" _
                    & " FROM [Data$]" _
                    & " GROUP BY [Data$].[" & datacols(d) & "]"

        ' OPEN RECORDSET '
        rst.Open strSQL, conn

        ' COLUMN HEADERS '
        If d = 1 Then
            i = 0
            Worksheets("RESULTS").Range("A1").Activate
            For Each fld In rst.Fields
                ActiveCell.Offset(0, i) = fld.Name
                i = i + 1
            Next fld
        End If

        ' DATA ROWS '
        lastrow = Worksheets("RESULTS").Cells(Worksheets("RESULTS").Rows.Count, "A").End(xlUp).Row
        Worksheets("RESULTS").Range("A" & lastrow + 1).CopyFromRecordset rst

        rst.Close
    Next d

    conn.Close

    MsgBox "Successfully processed SQL query!", vbInformation
    Exit Function

ErrHandle:
    MsgBox Err.Number & " - " & Err.Description, vbCritical
    Exit Function
End Function

输出