Linq使用多列进行高级查询

时间:2014-10-15 23:27:09

标签: c# sql asp.net linq

在我的ASP.NET项目中,我有一个名为BrowserStats的数据表,其中包含不同用户的不同浏览器列表。 我想按用户ID对用户进行分组,并使用linq显示特定浏览器(Chrome,Firefox,IE)的访问次数。
我的数据表(BrowserStats)如下:

UserId      |   Browser
----------------------------
1           |   Chrome-32.0
1           |   Chrome-30.0
1           |   Chrome-33.0
1           |   Firefox-20.0
1           |   Firefox-26.0
1           |   Safari 
1           |   IE-9
1           |   IE-10
2           |   Chrome-31.0
2           |   Chrome-32.0
2           |   IE-10
2           |   Firefox-22.0
2           |   Firefox-26.0

我的输出表应该是:

UserId      | Chrome |  Firefox |  IE | Others
-----------------------------------------------
1           |   3    |      2   |   2 |     1
2           |   2    |      2   |   1 |     0
  1. 如何在linq中查询此输出?
  2. linq是一种更快的方式,还是我应该在数据库中使用此查询编写存储过程并从C#中调用它?
  3. 是否有关于高级linq查询的优秀教程?

3 个答案:

答案 0 :(得分:3)

您可以在LINQ中使用嵌套组: -

var query = from browser in browesers
                        group browser by browser.UserID into UserGroup
                        from countGroup in
                            (from brow in UserGroup
                             group brow by new
                                 {
                                     Chrome = brow.Browser.Contains("Chrome"),
                                     Firefox = brow.Browser.Contains("Firefox"),
                                     IE = brow.Browser.Contains("IE")
                                 } into test
                                     select new
                                     {
                                         ChromeCount = test.Key.Chrome ? test.Count() : 0,
                                         FirefoxCount = test.Key.Firefox ? test.Count() : 0,
                                         IECount = test.Key.IE ? test.Count() : 0,
                                         OthersCount = (!test.Key.Chrome && !test.Key.Firefox && !test.Key.IE) ? test.Count() : 0
                                     }
                                 )
                        group countGroup by UserGroup.Key;

我使用了以下类型: -

public class BrowserInfo
    {
        public int UserID { get; set; }
        public string Browser { get; set; }
    }

这是工作Fiddle

答案 1 :(得分:2)

首先,我会考虑LINQ慢。 LINQ几乎是一种嵌套数组迭代逻辑的简洁方法。仅在CPU必须操作静态数据时使用。或数据是CPU生成的,没有后备存储。

无论如何,我是怎么想的。现在回答:

我已经在SQLServer 2012 Express中构建了一个用于恶魔条纹目的的数据库(< -Xanth reference)。我使用了你的浏览器并创造了虚构的用户。数据透视代码应该是您从c#调用的存储过程。如果您正在使用VS我可以编辑纯VS(2012)解决方案,因为我更喜欢使用数据集并向TableAdapter添加查询以使用存储过程。但这应该让你在那里2 / 3rds

用户表::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::

user table

浏览器表::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::

browser table

使用表样本(总共324行):::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::

usage table

图:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::

SQL diagram

PIVOT(我将其作为存储过程添加):::::::::::::::::::::::::::::::::::::::::::::::::: :::::::

the pivot result

VS 2012 / WPF实施::::::::::::::::::::::

添加存储过程后,将VS连接到数据库,并将数据集添加到项目中。将存储过程拖放到数据集中。您也可以使用没有类型化数据集生成器的存储过程。 See Here

vs dataset

WPF XAML ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::

<Window x:Class="WPFPIVOT.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <DataGrid Name="datagrid" ItemsSource="{Binding}"/>
</Grid>
</Window>

的.cs ::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace WPFPIVOT
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    Pivot pivoted;
    PivotTableAdapters.GetUsageTableAdapter adapter;


    public MainWindow()
    {
        InitializeComponent();

        //this code is the same for WPF and FORMs
        pivoted = new Pivot();
        adapter = new PivotTableAdapters.GetUsageTableAdapter();
        adapter.Fill(pivoted.GetUsage);
        ///////////////////////////////////////////////////////////////


        datagrid.DataContext = pivoted;
    }


}
}
WPF WINDOW ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::

(UserID列默认为最右边的列,select语句可以是select p1.UserID,p1[1],... p.[n]

the wpf window

答案 2 :(得分:2)

如果你想使用LINQ。它动态地将列和行添加到数据表。输出是数据格式

DataTable dt = new DataTable();
        dt.Columns.AddRange(new DataColumn[] { new DataColumn("Browser", Type.GetType("System.String")), new DataColumn("userid", Type.GetType("System.String")) });
        dt.Rows.Add(new object[] {"Chrome-32.0","1" });
        dt.Rows.Add(new object[] { "Chrome-32.0", "1" });
        dt.Rows.Add(new object[] { "Firefox-20.0", "1" });
        dt.Rows.Add(new object[] { "Firefox-26.0", "1" });
        dt.Rows.Add(new object[] { "Safari", "1" });
        dt.Rows.Add(new object[] { "IE-9", "1" });
        dt.Rows.Add(new object[] { "IE-10", "1" });
        dt.Rows.Add(new object[] { "Chrome-31.0", "2" });
        dt.Rows.Add(new object[] { "Chrome-32.0", "1" });
        dt.Rows.Add(new object[] { "IE-10", "1" });
        dt.Rows.Add(new object[] { "Firefox-22.0", "2" });

        DataTable dtOutPut = new DataTable();
        dtOutPut.Columns.Add(new DataColumn("UserID", Type.GetType("System.String")));
        var tableColumnName = dt.AsEnumerable().Select(s => s.Field<string>("Browser").Trim().ToLower().Split('-')[0].Trim()).Distinct();
        foreach (var item in tableColumnName)
        {
            dtOutPut.Columns.Add(new DataColumn(item, Type.GetType("System.String")));
        }

        var usrid = dt.AsEnumerable().Select(s => s.Field<string>("userid").Trim()).Distinct();

        Parallel.ForEach(usrid, (s) => {

            DataRow rec = dtOutPut.NewRow();
            rec["UserID"] = s;
            foreach (var item in tableColumnName)
            {
                rec[item] = dt.AsEnumerable().Where(s1 => s1.Field<string>("Browser").Trim().ToLower().Contains(item) && s1.Field<string>("userid") == s).Count();

            }

            dtOutPut.Rows.Add(rec);
        });

输出:

enter image description here