C#制作交叉表

一个程序中需要做一个交叉表,就是行和列都是数据库是字段的值,而非字段名称。

例如数据库有一个考试成绩表,有4列:学生名,课程名,成绩,年级。结构和数据如下图。

a

以上数据按照年级和科目进行分组汇总计算总分,得到以下数据。

b

一个典型的交叉表如下图,列标题为课程,行标题为年级,数据区域为各年级各门课程的总成绩。当然这些数据没有什么实际意义,仅是为了演示交叉表。

c

为了从原始的数据得到交叉表所示的数据,有几种方式,第1种可以用SQL Server提供的PIVOT函数,我对此不熟,简单看了一下,感觉缺乏灵活性差,需要列标题(也就是按列分组的值)写死到SQL语句中。第2种可以用C#代码生成具有指定格式的DataTable,然后再绑定到GridView控件。这种方式更加通用和灵活。本文采取第2种方式。

在第2种方式中,首先将所有数据根据要得到的交叉表行、列进行分组汇总,在本例中就是对年级和课程进行分组汇总,然后找出所有不同的年级和课程,创建一个DataTable,将课程名作为DataTable的列,将不同年级作为DataTable中的行,将某课程、某年级的成绩汇总作为DataTable对应行列的值,这样就得到一个拥有所需交叉表数据的DataTable。然后再创建一个GridView,列标题就是各个课程名称(第0列除外,为固定的“年级”2字),将DataTable绑定到GridView中,就最终得到了如图所示的交叉表了。

代码如下。

protected void Button2_Click(object sender, EventArgs e)
{
//先将数据根据要生成的交叉表的行和列进行分组汇总
var q = from g in
(from t in list
group t by new { t.grade,t.lesson }
)
select new { lesson = g.Key.lesson, grade=g.Key.grade, sum=g.Sum(t=>t.score)};
var list2 = q.ToList();
grid2.DataSource = list2;
grid2.DataBind();
//创建DataTable
DataTable table = new DataTable();
//得到行和列标题 及数量
int[] grades = list2.Select(t => t.grade).Distinct().ToArray();
string[] lessons = list2.Select(t => t.lesson).Distinct().ToArray();
//表中第一行第一列交叉处一般显示为第1列标题
table.Columns.Add(new DataColumn("年级"));
//表中后面每列的标题其实是列分组的关键字
for (int i = 0; i < lessons.Length; i++)
{
DataColumn column = new DataColumn(lessons[i]);
table.Columns.Add(column);
}
//为表中各行生成数据
for (int i = 0; i < grades.Length; i++)
{
var row = table.NewRow();
//每行第0列为行分组关键字
row[0] = grades[i];
//每行的其余列为行列交叉对应的汇总数据
for (int j = 0; j < lessons.Length; j++)
{
double num = list2.Where(t => t.grade == grades[i] && t.lesson == lessons[j]).Select(t => t.sum).FirstOrDefault();
row[lessons[j]] = num;
}
table.Rows.Add(row);
}
grid3.DataSource = table;
grid3.DataBind();
}

生成测试数据的代码。

    public class Exam
{
public string student { get; set; }
public string lesson { get; set; }
public double score { get; set; }
public int grade { get; set; }
public static List<Exam> randomList(int studentNum,int lessonNum)
{
Random r = new Random();
List<Exam> list = new List<Exam>(studentNum*lessonNum);
string[] lessons = { "高等数学", "大学语文", "大学英语", "程序设计基础", "数据库基础", "微机原理", "数据结构" };
string[] studens = new string[studentNum];
for (int i = 0; i < studentNum; i++)
studens[i] = randomName(r);
int t1;
for (int i = 0; i < studentNum; i++)
{
t1 = r.Next(3);
for (int j = 0; j < lessonNum; j++)
{
list.Add(new Exam { student = studens[i], grade=t1, lesson = lessons[j], score = r.Next(50, 100) });
}
}
return list;
}
public override string ToString()
{
return string.Format("name:{0,3}\tlesson:{1,8}\tscore:{2}", student, lesson, score);
}
private static string randomName(Random r)
{
string s = "他称已责成有关部门迅速制订校车安全条例抓紧完善校车标准做好校车工作所需资金由中央和地方财政分担多方筹集";
int len = s.Length;
int n = r.Next(2, 4);
string result = "";
for (int i = 0; i < n; i++)
{
result += s[r.Next(len)];
}
return result;
}
}
posted @ 2011-12-01 19:58  基础软件  阅读(3771)  评论(0编辑  收藏  举报