如何在Linq和SQL中将行转换为列

use*_*306 13 .net linq asp.net-mvc

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

language keyName keyValue
English    City    AA
Swedish    City    AAswedish
German     City    AAger
Chines     City    AAchines
French     City    AAfr
Spanish    City    AAspanish
Run Code Online (Sandbox Code Playgroud)

如何将Languagemaster表转换为下表

keyName  English Swedish   German  Chines   French  Spanish            
City      AA     AAswedish AAger   AAchines AAfr    AAspanish
Run Code Online (Sandbox Code Playgroud)

请告诉我如何在SOL和LinQ中编写查询.

Ser*_*kiy 26

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

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;
}
Run Code Online (Sandbox Code Playgroud)

用法:

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

它有三个参数:

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

结果:

在此输入图像描述


原始答案:

此查询将返回数据的轴.查询中的每个项目都有Name(例如,在您的示例中为"城市")和值列表 - 每个透视列的一个值(即对于每种语言,我们将包含包含语言名称的值作为ColumnValue)

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
                         }
            };
Run Code Online (Sandbox Code Playgroud)

如何从此查询构建数据表

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);
}
Run Code Online (Sandbox Code Playgroud)