带有 VBA Excel 的 SQL 数据透视函数文本文件数据库

Posted

技术标签:

【中文标题】带有 VBA Excel 的 SQL 数据透视函数文本文件数据库【英文标题】:SQL pivot function text file database with VBA Excel 【发布时间】:2016-07-15 15:45:12 【问题描述】:

我们在工作中无法访问 SQL 服务器,因此我必须在 Excel VBA 中设计一个应用程序并使用文本文件 (CSV) 来存储数据。

我在查询数据、加入 CSV 时没有问题,但我想使用 SQL Pivot/Unpivot 语句将其中一列转换为行。我不确定该功能是否存在,因为我不断收到 FROM 子句中存在语法错误的错误。

    Public Function getData() As ADODB.Recordset

    Dim path As String, conn As ADODB.Connection, rs As ADODB.Recordset
    path = ThisWorkbook.path & "\"

    Set conn = New ADODB.Connection
    Set rs = New ADODB.Recordset

    conn.Open ("Provider=Microsoft.Jet.OLEDB.4.0;" & _
               "Data Source=" & path & ";" & _
               "Extended Properties=""text; HDR=Yes; FMT=Delimited; IMEX=1;""")

    rs.ActiveConnection = conn
    rs.Source = "SELECT * " & _
                "FROM " & _
                    "(SELECT emp_id, client, allocation " & _
                    "FROM ALLOCATIONdb.csv) AS s " & _
                "PIVOT (SUM(allocation) FOR client IN (client1, client2)) AS pvt"

    Set getData = rs

End Function

My data currently looks like the top of the picture and I want it to look like the bottom.

使用数据透视表很简单,但我希望用户能够输入数据。

此外,是否有使其动态化,因为可能的客户端数量未知,因此需要扩展行数。

提前致谢

【问题讨论】:

您怀疑 Pivot 功能在 Jet 中不可用。您可以通过搜索找到替代方案。我认为他们通常在 VBA 中使用 UNION ALL 和循环。我有一个帖子可以做到这一点:yoursumbuddy.com/data-normalizer-the-sql @DougGlancy 在 Jet 中有一个支点(实际上比 SQL 服务器早几年),但 OP 需要使用 TRANSFORM 关键字。例如***.com/a/8975437/119477 转换效果很好,谢谢! @ConradFrix,很高兴知道! @user2476784 您应该添加您的解决方案作为答案。我尝试让转换工作,但我不能 【参考方案1】:

这可能不是最好的解决方案,但它确实对我有用。 我将我的数据转换为一个列表,并将其传递给一个名为“ToDataTable”的函数,以首先转换为数据表。

public  DataTable ToDataTable<T>(List<T> items)
        
            DataTable dataTable = new DataTable(typeof(T).Name);
            PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo prop in Props)
            
                dataTable.Columns.Add(prop.Name , prop.PropertyType);
            
            foreach (T item in items)
            
                var values = new object[Props.Length];
                for (int i = 0; i < Props.Length; i++)
                
                    object val;
                    val = Props[i].GetValue(item, null);
                    values[i] = val;
                
                dataTable.Rows.Add(values);
            
            return dataTable;
        

然后使用 GetInversedDataTable() 函数将其转换为您想要的格式。

public static DataTable GetInversedDataTable(DataTable table, string columnX, 
     string columnY, string columnZ, string nullValue, bool sumValues)


    DataTable returnTable = new DataTable();

    if (columnX == "")
        columnX = table.Columns[0].ColumnName;

    returnTable.Columns.Add(columnY);
    List<string> columnXValues = new List<string>();

    foreach (DataRow dr in table.Rows)
    

        string columnXTemp = dr[columnX].ToString();
        if (!columnXValues.Contains(columnXTemp))
        

            returnTable.Columns.Add(columnXTemp);
        
    

    //Verify if Y and Z Axis columns re provided
    if (columnY != "" && columnZ != "")
    

        List<string> columnYValues = new List<string>();

        foreach (DataRow dr in table.Rows)
        
            if (!columnYValues.Contains(dr[columnY].ToString()))
                columnYValues.Add(dr[columnY].ToString());
        

        //Loop all Column Y Distinct Value
        foreach (string columnYValue in columnYValues)
        

            DataRow drReturn = returnTable.NewRow();
            drReturn[0] = columnYValue;
            DataRow[] rows = table.Select(columnY + "='" + columnYValue + "'");

            foreach (DataRow dr in rows)
            
                string rowColumnTitle = dr[columnX].ToString();

                foreach (DataColumn dc in returnTable.Columns)
                
                    if (dc.ColumnName == rowColumnTitle)
                    

                        if (sumValues)
                        
                            try
                            
                                drReturn[rowColumnTitle] = 
                                     Convert.ToDecimal(drReturn[rowColumnTitle]) + 
                                     Convert.ToDecimal(dr[columnZ]);
                            
                            catch
                            
                                drReturn[rowColumnTitle] = dr[columnZ];
                            
                        
                        else
                        
                            drReturn[rowColumnTitle] = dr[columnZ];
                        
                    
                
            
            returnTable.Rows.Add(drReturn);
        
    
    else
    
        throw new Exception("The columns to perform inversion are not provided");
    
    if (nullValue != "")
    
        foreach (DataRow dr in returnTable.Rows)
        
            foreach (DataColumn dc in returnTable.Columns)
            
                if (dr[dc.ColumnName].ToString() == "")
                    dr[dc.ColumnName] = nullValue;
            
        
    

    return returnTable;

像这样使用它:

DataTable dtReturn = GetInversedDataTable(dt, "client", "emp_id", 
                                          "allocation", "0", true);

提供三列并返回一个新的DataTable。

下面的示例将使用源表和下面的参数来构建数据透视表。 在您的情况下: X 轴列:“客户” Y 轴列:“emp_id” Z轴栏:“分配” 空值:“0”; 值总和:真

请注意,这是我用于解决问题的代码,我的代码是 C#

【讨论】:

【参考方案2】:
Public Function getData(db1 As String, db2 As String, var1 As String, var2 As String) As ADODB.Recordset

Dim path As String, conn As ADODB.Connection, rs As ADODB.Recordset
path = ThisWorkbook.path & "\"

Set conn = New ADODB.Connection
Set rs = New ADODB.Recordset

conn.Open ("Provider=Microsoft.Jet.OLEDB.4.0;" & _
           "Data Source=" & path & ";" & _
           "Extended Properties=""text; HDR=Yes; FMT=Delimited; IMEX=1;""")

rs.ActiveConnection = conn

rs.Source = "TRANSFORM sum(a.allocation) " & _
            "SELECT a.emp_id, b.name, b.[new title], b.[new department] " & _
            "FROM " & db1 & " a " & _
            "INNER JOIN " & db2 & " b " & _
            "ON a.emp_id = b.emp " & _
            "GROUP BY a.emp_id, b.name, b.[new title], b.[new department] " & _
            "ORDER BY b.[new department], b.[new title], b.name " & _
            "PIVOT a.client"

Set getData = rs

结束函数

Transform 最终完成了我需要的工作。

感谢您的帮助!

【讨论】:

这也是我想要执行的东西,请指导我您为 db1, db2, var1, var2 提供什么价值

以上是关于带有 VBA Excel 的 SQL 数据透视函数文本文件数据库的主要内容,如果未能解决你的问题,请参考以下文章

加快数据透视表过滤 VBA 代码

使用 VBA 过滤 Excel 数据透视表

取消透视 Excel 矩阵/数据透视表?

Excel 使用 VBA 遍历嵌套的数据透视表行字段

Excel 2007 VBA - 数据透视表字段列表???产生错误

新手向EXCEL高人请教关于VBA和数据透视图的问题,愿不吝赐教的学生先在这里给您道声:谢谢了.请留下您的Q...