在C#2005中如何实现数据库中交叉表的功能

时间:2022-10-23 09:54:55

在C#2005中如何实现数据库中交叉表的功能

摘要:交叉表的设计一直是程序开发的难点,充分利用C#2005数据集和数据表的离线功能,我们可以把一张表的数据行变成另一个内存表的数据列,这样我们就可以非常容易地进行数据汇总统计,统计要求符合中国报表特色。

关键词:离线模式;数据集;数据表;交叉表

中图法分类号:TP31 文献标识码:B 文章编号:1009-3044(2008)15-20ppp-0c

Implement CrossTable in C#2005

PANG Yi-fan

(WuXi High Vocational Education,Wuxi 214028,China)

Abstract:Cross-table design has been developed and difficult process,full use of C# 2005 dataset and datatable's offline function,we can transform datarows of one table into another datacolumns of memory table,so that we can be very easy data summary statistics, the statistical requirements in line with China's statements characteristics.

Key words:OffLine;DataSet;DataTable;CrossTable

1 下的离线模式

我们知道在C#2005中进行数据库开发的时候,需要利用技术进行开发,在之前,一般开发数据库程序的时候,都需要在线访问数据库服务器中的数据,也就是说客户端程序在运行的时候,都和远程的数据库服务器连接,直到关闭你的运行程序为止。这一种联机方式在局域网内没有什么问题,但是在今天以互联网为基础的环境下,就存在很大的弊端,主要原因就是客户连接到数据库是一种比较耗内存的资源,当有大量用户访问数据库服务器,服务器就会占据大量的内存,并且网络的传输效率会降低。为此提出了离线模式,就是为克服在线模式下的缺点而设计的,解决方法就是当用户需要数据的时候,连接数据库服务器,当数据下载到客户端的时候,马上断开与数据库服务器的连接,这样就节省了大量的资源。离线模式的技术解决之道用数据集来表示(DataSet),一个数据集可以存放任意数量的数据表(DataTable),而每一个DataTable之间还可以建立关系(TableRelation),有了这样的概念以后,我们可以认为一个DataSet就是一个数据库在客户端的副本。具体模式图表如下:

2 使用DataSet及DataTable:

DataSet其实就是数据集,已经说过DataSet是把数据库中的数据映射到内存缓存中所构成的数据容器,对于任何数据源,它都提供一致的关系编程模型。在DataSet中既定义了数据表的约束关系以及数据表之间的关系,还可以对数据表中的数据进行排序等。DataSet使用方法一般有三种:

1.把数据库中的数据通过DataAdapter(数据适配器)对象填充DataSet。

2.通过DataAdapter对象操作DataSet实现更新数据库。

3.把XML数据流或文本加载到DataSet。

2.1 建立SQL 2000数据表

下面就来详细探讨以上DataSet和DataTable配合使用方法的具体实现。我使用的利用DataAdapter对象填充DataSet,使用语言是C#,特别注意的是动态建立内存表成绩汇总表的建立过程。后台数据库是SQL 2000 Server(数据库文件是Test)。

Test中有三个表(学生表Stu,课程表Course,成绩表Score)

学生表内容如下:

课程表内容如下:

成绩表内容如下:

从成绩表我们可以查出任何一个人的每一门课程的成绩,但是如果要统计全班所有课程就比较困难;这时我们必须用到交叉表,但是交叉表在数据库中没有定义,编程人员必须利用技术在内存中动态生成如下的表格(成绩汇总表):

2.2 用C#2005创建动态表

(1)创建一个过程(CreateTable)来建立需要的表

private void CreateTable()

{Settings st = new Settings();

conn = new SqlConnection(st.Setting);//建立数据库连接

conn.Open();

dap = new SqlDataAdapter("select sno,sname from stu", conn);

dt = new DataTable("学生表");

ds = new DataSet();

dap.Fill(ds, "学生表");//内存中建立学生表,具有字段学号和姓名

dap = new SqlDataAdapter("select coursename from courseName ", conn);

dt = new DataTable("课程名称");

dap.Fill(ds, "课程名称");//建立课程表,只有字段课程名称

dt = new DataTable("分数表");

ds.Tables.Add("分数表");

//以下是动态的建立成绩汇总表,而不是用适配器来自动建立内存表,这时建立交叉表的关键

DataTabledt1 = new DataTable("成绩汇总表");

ds.Tables.Add("成绩汇总表");

ds.Tables["成绩汇总表"].Columns.Add("sno", typeof(System.String));

ds.Tables["成绩汇总表"].Columns["sno"].MaxLength = 6;

ds.Tables["成绩汇总表"].Columns.Add("sname", typeof(System.String));

ds.Tables["成绩汇总表"].Columns["sname"].MaxLength = 10;

string Express = string.Empty;

int count = ds.Tables["课程名称"].Rows.Count;

foreach (DataRow dr in ds.Tables["课程名称"].Rows)

{

ds.Tables["成绩汇总表"].Columns.Add((string)dr["coursename"], typeof(System.Double));

ds.Tables["成绩汇总表"].Columns[(string)dr["coursename"]].DefaultValue = 0;

Express += (string)dr["coursename"] + "+";

}

Express = Express.Substring(0, Express.Length - 1);

//建立计算字段

ds.Tables["成绩汇总表"].Columns.Add("总分", typeof(System.Double));

ds.Tables["成绩汇总表"].Columns["总分"].Expression = Express;

ds.Tables["成绩汇总表"].Columns.Add("平均分", typeof(System.Double));

ds.Tables["成绩汇总表"].Columns["平均分"].Expression = "总分/" + count.ToString();

DataColumn[] dc = new DataColumn[1];

dc[0] = ds.Tables["成绩汇总表"].Columns["sno"];

ds.Tables["成绩汇总表"].PrimaryKey = dc;//建立主关键字

//加数据

foreach (DataRow dr in ds.Tables["课程名称"].Rows)

{

//3表中找出每门课程对应的所有信息学号,姓名,课程号,课程名,分数

SqlDataAdapter dapFen = new SqlDataAdapter("select a.sno,a.sname,b.coursename,c.courseid,c.fen from stu a,course b,Score c where a.sno=c.sno and b.courseid=c.courseid and b.coursename='" + dr["coursename"].ToString() + "'", conn);

ds.Tables["分数表"].Rows.Clear();

dapFen.Fill(ds, "分数表");//建立分数表,(数学,物理,化学,语文)

foreach (DataRow drr in ds.Tables["分数表"].Rows)

{

DataRow drfind = ds.Tables["成绩汇总表"].Rows.Find(drr["sno"]);

if (drfind == null)//汇总表中没有相应的课程记录就添加

{

DataRow drd = ds.Tables["成绩汇总表"].NewRow();

drd["sno"] = drr["sno"];

drd["sname"] = drr["sname"];

drd[(string)dr["coursename"]] = drr["fen"];//课程名对应相应的成绩

ds.Tables["成绩汇总表"].Rows.Add(drd);

}

else//有记录就修改其分数

{

//找到的记录所在的行位置

int i = ds.Tables["成绩汇总表"].Rows.IndexOf(drfind);ds.Tables["成绩汇总表"].Rows[i][(string)dr["coursename"]] = drr["fen"];

}

}

}

conn.Close();//断开连接,进入离线模式

}

(2)建立过程CreteField来建立DataGridView的列和内存表(成绩汇总表的绑定关系)

private void CreateField()

{

Grid.Columns.Add("c1", "学号");

Grid.Columns["c1"].DataPropertyName = "sno"; //数据绑定

Grid.Columns["c1"].Width = 75;

Grid.Columns["c1"].Frozen = true;//冻结列

Grid.Columns.Add("c2", "姓名");

Grid.Columns["c2"].DataPropertyName = "sname";

Grid.Columns["c2"].Width = 65;

Grid.Columns["c2"].Frozen = true;

int i = 3;

foreach (DataRow dr in ds.Tables["课程名称"].Rows)

{

Grid.Columns.Add("c" + i.ToString(), (string)dr["coursename"]);

Grid.Columns["c" + i.ToString()].DataPropertyName = (string)dr["coursename"];

Grid.Columns["c" + i.ToString()].Width = 80;

i++;

}

Grid.Columns.Add("总分", "总分");

Grid.Columns["总分"].DataPropertyName = "总分";

Grid.Columns["总分"].Width = 80;

Grid.Columns.Add("平均分", "平均分");

Grid.Columns["平均分"].DataPropertyName = "平均分";

Grid.Columns["平均分"].Width = 80;

Grid.DataSource = ds.Tables["成绩汇总表"];

(3)我们只需要在窗体的OnLoad事件中调用上面定义的两个过程即可,具体代码如下:

public partial class FrmHZ : Form

{ SqlConnection conn;

SqlDataAdapter dap;

DataSet ds;

DataTable dt;

string SQLStr = string.Empty;

//以上定义的窗体级成员

public FrmHZ()

{

InitializeComponent();

}

private void FrmHZ_Load(object sender, EventArgs e)

{

CreateTable();

CreateField();

}

}

3 结束语

交叉表在数据统计中占有比较重要的地位,但是数据表中并不存在交叉表,所以需要我们根据现成的表来动态建立内存中的交叉表。利用DataTable对象中Columns集合来动态建立交叉表的数据列,而该数据列来自数据表Course的行内容。(当我们在课程表中加上一门新的课程的时候,交叉表中的内容会自动变化)

参考文献:

[1]黄忠成.Framework的设计与应用[M].北京:电子工业出版社,2006年1月,90-165.

[2]高级编程[M] (美)Glenn Johnson 北京:清华大学出版社,2006年6月50-198.

[3]代方震.Visual C# 2005程序设计.北京:人民邮电出版社,2007年9月,206-243.

收稿日期:2008-2-18

作者简介:庞一凡(1965-),江苏无锡人,无锡机电高等职业技术学校信息系教师,软件工程师,研究方向:计算机软件开发(C#.Net,Delphi 和SQL Server下的网络数据库程序开发)。

上一篇:浅谈ERP课程教学及实验 下一篇:基于构件的软件测试方法概述