16

我有一张名为Languagemaster的表,记录如下

language keyName keyValue
English    City    AA
Swedish    City    AAswedish
German     City    AAger
Chines     City    AAchines
French     City    AAfr
Spanish    City    AAspanish

如何将Languagemaster表转换为下表

keyName  English Swedish   German  Chines   French  Spanish            
City      AA     AAswedish AAger   AAchines AAfr    AAspanish

请让我知道如何在 SOL 和 LinQ 中编写查询。

4

3 回答 3

34

更新:我创建了以下通用方法,可以从任何集合构建数据透视表

public static DataTable ToPivotTable<T, TColumn, TRow, TData>(
    this IEnumerable<T> source,
    Func<T, TColumn> columnSelector,
    Expression<Func<T, TRow>> rowSelector,
    Func<IEnumerable<T>, TData> dataSelector)
{
    DataTable table = new DataTable();
    var rowName = ((MemberExpression)rowSelector.Body).Member.Name;
    table.Columns.Add(new DataColumn(rowName));
    var columns = source.Select(columnSelector).Distinct();

    foreach (var column in columns)
        table.Columns.Add(new DataColumn(column.ToString()));

    var rows = source.GroupBy(rowSelector.Compile())
                     .Select(rowGroup => new {
                         Key = rowGroup.Key,
                         Values = columns.GroupJoin(
                             rowGroup,
                             c => c,
                             r => columnSelector(r),
                             (c, columnGroup) => dataSelector(columnGroup))
                     });

    foreach (var row in rows) {
        var dataRow = table.NewRow();
        var items = row.Values.Cast<object>().ToList();
        items.Insert(0, row.Key);
        dataRow.ItemArray = items.ToArray();
        table.Rows.Add(dataRow);
    }

    return table;
}

用法:

var table = Languagemaster.ToPivotTable(
                item => item.language,
                item => item.keyName,
                items => items.Any() ? items.First().keyValue : null);

它有三个参数:

  • 在您的情况下选择列(即列标题中的内容)的列属性选择器是不同的语言值,但它可以是其他任何值,例如日期。
  • 行属性选择器- 是一个将出现在行标题中的值,这是每行将相关的内容。请记住 - 它是表达,而不是简单的代表。我们需要它来设置第一列的列名。
  • 数据选择器- 这是一种将在每个单元格的分组数据上运行的方法。即在您的情况下,我们只选择keyValue组中第一项的属性。但它可能是物品数量items => items.Count()或其他任何东西。

结果:

在此处输入图像描述


原始答案:

此查询将为您的数据返回数据透视。查询中的每个项目都将具有Name(即您的示例中的“城市”)和值列表 - 每个数据透视列都有一个值(即,对于每种语言,我们将具有包含语言名称Column和的值Value

var languages = Languagemaster.Select(x => x.language).Distinct();
var query = from r in Languagemaster
            group r by r.keyName into nameGroup
            select new {
                Name = nameGroup.Key,
                Values = from lang in languages
                         join ng in nameGroup 
                              on lang equals ng.language into languageGroup
                         select new {
                             Column = lang,
                             Value = languageGroup.Any() ? 
                                     languageGroup.First().keyValue : null
                         }
            };

如何从此查询构建数据表

DataTable table = new DataTable();
table.Columns.Add("keyName");  // first column
foreach (var language in languages)
    table.Columns.Add(language); // columns for each language

foreach (var key in query)
{
    var row = table.NewRow();
    var items = key.Values.Select(v => v.Value).ToList(); // data for columns
    items.Insert(0, key.Name); // data for first column
    row.ItemArray = items.ToArray();
    table.Rows.Add(row);
}
于 2013-07-31T14:12:08.730 回答
2

这是基于多列对数据进行分组的代码。

        testDt = GetTestDate();
        var data2 = testDt.Tables[0].AsEnumerable().Select(x => new
        {
            Family = x.Field<int>("tdFamily"),
            Class = x.Field<short>("luClass"),
            Region = x.Field<short>("luRegion"),
            Year = x.Field<int>("tdYear"),
            Population = x.Field<decimal>("tdPopulation ")
        });

        DataTable pivotDataTable = data2.ToPivotTable(
             item => item.Year,
            item => new{ item.Family, item.Class, item.Region},
            items => items.Any() ? items.Sum(x => x.Allocation) : 0
            );

         public static DataTable ToPivotTable<T, TColumn, TRow, TData>(
         this IEnumerable<T> source,
         Func<T, TColumn> columnSelector,
         Expression<Func<T, TRow>> rowSelector,
         Func<IEnumerable<T>, TData> dataSelector)
    {
        DataTable table = new DataTable();
        var rowsName = ((NewExpression)rowSelector.Body).Members.Select(s => s).ToList();
        foreach (var row in rowsName)
        {
            var name = row.Name; 
            table.Columns.Add(new DataColumn(name));
        }
        var columns = source.Select(columnSelector).Distinct();
        foreach (var column in columns)
            table.Columns.Add(new DataColumn(column.ToString()));
        var rows = source.GroupBy(rowSelector.Compile())
                         .Select(rowGroup => new
                         {
                             Key = rowGroup.Key,
                             Values = columns.GroupJoin(
                                 rowGroup,
                                 c => c,
                                 r => columnSelector(r),
                                 (c, columnGroup) => dataSelector(columnGroup))
                         });

        foreach (var row in rows)
        {
            var dataRow = table.NewRow();
            var items = row.Values.Cast<object>().ToList();
            string[] keyRow = row.Key.ToString().Split(',');
            int index = 0;
            foreach (var key in keyRow)
            {
                string keyValue = key.Replace("}", "").Split('=')[1].Trim();
                items.Insert(index, keyValue);
                index++;
            }
            dataRow.ItemArray = items.ToArray();
            table.Rows.Add(dataRow);
        }
        return table;
    }
}
于 2019-07-05T11:33:47.363 回答
0
public static DataTable XToPivotTable<T, TColumn, TRow, TData>(this IEnumerable<T> source, Func<T, TColumn> columnSelector, Expression<Func<T, TRow>> rowSelector, Func<IEnumerable<T>, TData> dataSelector) {
      DataTable table = new DataTable();

      if (rowSelector.Body is NewExpression) {
        var rowNames = ((NewExpression)rowSelector.Body).Members.ToList();
        rowNames.ForEach(s => table.Columns.Add(new DataColumn(s.Name, s.DeclaringType.GetProperty(s.Name).PropertyType)));
      } else {
        var rowName = ((MemberExpression)rowSelector.Body).Member;
        table.Columns.Add(new DataColumn(rowName.Name, rowName.DeclaringType.GetProperty(rowName.Name).PropertyType));
      }

      var columns = source.Select(columnSelector).Distinct();

      foreach (var column in columns)
        table.Columns.Add(new DataColumn(column.ToString()));

      var rows = source.GroupBy(rowSelector.Compile())
        .Select(rg => new {
          rg.Key,
          Values = columns.GroupJoin(rg, c => c, r => columnSelector(r), (c, cg) => dataSelector(cg))
        });

      foreach (var row in rows) {
        var dataRow = table.NewRow();
        var items = TypeDescriptor.GetProperties(typeof(TRow)).Cast<PropertyDescriptor>().Select(s => s.GetValue(row.Key)).ToList();
        items.AddRange(row.Values.Cast<dynamic>());
        dataRow.ItemArray = items.ToArray();
        table.Rows.Add(dataRow);
      }

      return table;
    }
于 2019-07-11T05:38:38.367 回答