使用Pivot进行枢轴输入

时间:2013-12-25 14:40:15

标签: hadoop pivot apache-pig

在下面的情况下我需要你的帮助(使用Pig Latin)。

我有以下格式的输入数据:

DATE,ERROR,COUNT
20110212,ORA-00600,9
20110212,ORA-03135,1
20110226,ORA-20000,1
20110305,ORA-03135,1
20110319,ORA-01555,1
20110319,ORA-03135,18
20110326,ORA-00600,1
20110409,ORA-00600,1
20110416,ORA-20000,1
20110423,ORA-01555,2
20110507,ORA-00600,1
20110507,ORA-01555,2
20110514,ORA-00600,1
20110514,ORA-03135,4

我正在寻找下面的输出。

DATE,ORA-00600,ORA-03135,ORA-20000....
20110212,9,1,0....
20110514,1,4,0...
20110416,0,0,1...

基本上,我希望透视输入数据;我无法使用嵌套的FOREACH(带过滤器),因为错误代码(如ORA-00600,ORA-03135 ..)不是常量,而是动态的。

请建议。

1 个答案:

答案 0 :(得分:0)

关于SQL中的PIVOT功能有多少问题,我并不感到惊讶。我也有一些需要使用PIVOT结果的项目。电子表格是一个完美的例子(并且是企业IT世界的巨大需求)。

数据透视表非常棒,但如果您像我一样在动态制造环境中工作,它们通常会变得繁琐复杂。在这种领域中,需求总是主观的。并且可以让程序员从根部拉出他的头发。

正是由于这个原因,我决定在DataTable对象上创建一个扩展,它产生了一个我发现既快又有用的PIVOT表。

是的,我知道SQL版本,并且我知道有很多方法可以使SQL中的PIVOT更具动态性(用于更改列)。但我学会了保持简单。简单性就是稳定性,可用性,可扩展性和可扩展性。这些都是真正企业界的巨大优势。

我现在和你分享这个,希望你能修改它以满足你的需求。它是动态的,非常快......最好的SIMPLE。

/// <summary>
/// Creates a PIVOT table based on values in existing table
/// </summary>
/// <param name="PKey">Field used as PIVOT tables Primary (row) Key.</param>
/// <param name="FKey">Field used to create unique column names in PIVOT table.</param>
/// <param name="VKey">Field used as the value for each associated column in a PIVOT table record.</param>
/// <returns>DataTable</returns>
public static DataTable Pivot(this DataTable tbl, string PKey, string FKey, string VKey)
    {
        DataTable retVal = null;
        DataTable keyTbl = null;
        DataTable fldTbl = null;
        DataColumn dc = null;
        DataRow newRow = null;

        Type pkType = null;
        Type valType = null;

        string strPkeyFilter = null;
        string prevFilter = null;

        try
        {
            // Get previous filter (save)
            prevFilter = tbl.DefaultView.RowFilter;

            if (tbl.Rows.Count > 0)
            {
                // Get unique Primary Keys and Field Names
                keyTbl = tbl.DefaultView.ToTable(true, PKey);
                fldTbl = tbl.DefaultView.ToTable(true, FKey);

                if (fldTbl.Rows.Count > 0)
                {
                    // Get Primary Key data type and create column on Pivot table.
                    pkType = tbl.Columns[PKey].DataType;
                    retVal = new DataTable(tbl.TableName);
                    retVal.Columns.Add(new DataColumn(PKey, pkType));
                    retVal.PrimaryKey = new DataColumn[] { retVal.Columns[PKey] };

                    // Get VALUE columns data type
                    valType = tbl.Columns[VKey].DataType;

                    // Create Primary Key filter
                    strPkeyFilter = "{0} = {1}";
                    if(pkType.Equals(typeof(string)))
                        strPkeyFilter = "{0} = '{1}'";

                    foreach (DataRow dr in fldTbl.Rows)
                    {
                        // Create additional rows in Pivot table based on unique Field Names
                        dc = new DataColumn(Convert.ToString(dr[FKey]), valType);
                        dc.AllowDBNull = true;
                        dc.DefaultValue = DBNull.Value;
                        retVal.Columns.Add(dc);
                    }

                    // Iterate through Primary Key collection
                    foreach (DataRow dr in keyTbl.Rows)
                    {
                        // Set Primary Key row filter on base table
                        tbl.DefaultView.RowFilter = string.Format(strPkeyFilter, PKey, dr[PKey]);
                        if (tbl.DefaultView.Count > 0)
                        {
                            // Create new row on Pivot table and set Primary Key
                            newRow = retVal.NewRow();
                            newRow[PKey] = dr[PKey];

                            // Iterate through records and find VALUE for each FIELD column
                            foreach (DataRowView drv in tbl.DefaultView)
                                newRow[Convert.ToString(drv[FKey])] = drv[VKey];

                            retVal.Rows.Add(newRow);
                        }
                    }

                    // Return previous row filter on base table
                    tbl.DefaultView.RowFilter = prevFilter;
                    // Commit chages to Pivot table (if any)
                    retVal.AcceptChanges();
                }
            }
        }
        catch (Exception)
        {

            throw;
        }
        finally
        {
            if (keyTbl != null)
                keyTbl.Dispose();
            if (fldTbl != null)
                fldTbl.Dispose();
        }

        return retVal;
    }

用法很简单,因为它是DataTable对象的扩展方法:

DataTable dt = myTbl.Pivot("DOC_ID", "UI_FIELD", "UI_VALUE");

如果 myTbl 的布局如下:

DOC_ID  |  ENTRY_DATE  |  UI_FIELD  |  UI_CAPTION  |  UI_VALUE
----------------------------------------------------------------
  1        01/01/2015    EMPL_NAME    Empl. Name     John Doe
  1        01/01/2015    EMPL_PHONE   Empl. Phone    801-555-1212
  1        01/01/2015    EMPL_MNGR    Empl. Mangr.   Jane Doe

它将返回:

DOC_ID  |  ENPL_NAME  |  EMPL_PHONE  | EMPL_MNGR
-------------------------------------------------
  1        John Doe     801-555-1212   Jane Doe

在垂直行中布置UI条目数据的好处(在制造环境中无论如何)是为了更好地适应UI字段添加或减少..这种情况很多!因为您要做的最后一件事是修改数据模式。特别是当大约一百个(已知和未知)应用程序也在使用它时。

无论如何,以及它的价值,我希望这会让你朝着理想的方向前进。我经常使用它。