实现要点:
1。读取所有目标成绩(flatScroreTable)
2。从目标成绩中提取考试时间(不重复),作为交叉表的列表头
3。从目标成绩中提取考试科目(不重复),作为交叉表的行表头
4。根据2动态构建一个DataTable(crossScroreTable),此DataTable具有一个科目列,若干考试时间列,以及其他信息。
5。将3中的考试科目写入DataTable
6。从flatScroreTable中读取成绩值填入crossScroreTable对应单元格
说明:便于理解,这里将交叉表crossScroreTable想象成一张Excel表,列名就当作列表头,科目名就当作行表头。
主要代码:
void
LoadScoreData()
{
读取指定学生的所有成绩#region 读取指定学生的所有成绩
string stuName = drpStu.SelectedValue;
string connStr = "SERVER=.;DATABASE=DemoLib;UID=sa";
string sql = "SELECT SubjectName, StudentName, ScoreValue, ExamDate FROM t_Score WHERE StudentName = @StuName";
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(sql, connStr);
da.SelectCommand.CommandType = CommandType.Text;
da.SelectCommand.Parameters.Add("@StuName", stuName);
da.Fill(ds, "FlatScore");
#endregion 读取指定学生的所有成绩
DataTable flatScoreTable = ds.Tables[0];
DataView flatScoreView = new DataView(flatScoreTable);
// 读取科目列表,排除重复
DataTable subjectList;
// .NET 2 using the ToTable method supported by DataView
//subjectList = flatScoreView.ToTable("SubjectList", true, "SubjectName");
subjectList = SelectDistinct(flatScoreTable, "SubjectList", true, "SubjectName");
// 读取考试时间列表,排除重复
// .NET 2
DataTable examDateList;
// .NET 2 using the ToTable method supported by DataView
//examDateList = flatScoreView.ToTable("ExamDateList", true, "ExamDate");
examDateList = SelectDistinct(flatScoreTable, "ExamDateList", true, "ExamDate");

创建 交叉表#region 创建 交叉表
DataTable crossScoreTable = new DataTable();

构造表模式#region 构造表模式
// 科目 列
crossScoreTable.Columns.Add("科目", typeof(string));
// 考试时间 列,以时间为列名
foreach (DataRow r in examDateList.Rows)
{
crossScoreTable.Columns.Add(((DateTime)r[0]).ToString("yyyy年M月dd日"), typeof(string));
}
#endregion 构造表模式

从成绩表读取并写入数据#region 从成绩表读取并写入数据
DataColumnCollection cols = crossScoreTable.Columns;
// 按先科目(行)后时间(列)遍历 
foreach (DataRow r in subjectList.Rows)
{
DataRow newRow = crossScoreTable.NewRow();
// 科目
newRow[0] = r[0];
// 成绩,遍历时间
for(int i=1; i< cols.Count; i++)
{
// 返回具有指定科目和指定考试的成绩
// eg. "SubjectName='孙光' AND ExamDate='2007-5-19'"
flatScoreView.RowFilter = String.Format("SubjectName='{0}' AND ExamDate='{1}'", r[0], examDateList.Rows[i-1][0]);
if (flatScoreView.Count > 0)
{
newRow[cols[i]] = flatScoreView[0]["ScoreValue"];
}
}
// 加入新表
crossScoreTable.Rows.Add(newRow);
}
#endregion 从成绩表读取并插入数据
#endregion 创建 交叉表
// 绑定,输出数据
grdCrossScore.DataSource = crossScoreTable;
grdCrossScore.DataBind();
grdFlatScore.DataSource = flatScoreTable;
grdFlatScore.DataBind();
grdSubjectList.DataSource = subjectList;
grdSubjectList.DataBind();
grdExamDate.DataSource = examDateList;
grdExamDate.DataBind();
}
看下这个方法:
DataTable SelectDistinct(DataTable sourceTable,
string
newTableName,
bool
distinct,
params
string
[] columnNames)
如果 ADO.NET 2.0 中我们就可以直接使用 DataView 的 ToTable 方法的重载版本:
public
DataTable ToTable(
bool
distinct,
params
string
[] columnNames);
public
DataTable ToTable(
string
tableName,
bool
distinct,
params
string
[] columnNames);
SelectDistinct 网上有很多版本,原理基本一样,只是效率问题,这里是修改于 Erik Porter 的 Select DISTINCT on DataTable。
SelectDistinct完整代码:

implements such as 'SELECT DISTINCT Column0, Column1
' sql clause for DataTable.#region implements such as 'SELECT DISTINCT Column0, Column1
' sql clause for DataTable. 
/**//*
* The implement detail refers to http://weblogs.asp.net/eporter/archive/2005/02/10/370548.aspx. Many thanks to Erik Porter.
* NOTE:The .NET 2.0's DataView provider a ToTable method that will build a DataTable based off of the current DataView and
* also allow you to specify which columns you want in the DataTable as all as being able to say Distinct rows only.
* So, recommends to consume the override method directly as following:
* <example>
* DataTable srcTable;
* // 
* DataView srcView = srcTable.DefaultView;
* DataTable dstTable = srcView.ToTable("NewTableName", true, "ColumnName1", "ColumnName2", "ColumnNameN");
* </example>
*/
private static DataTable SelectDistinct(DataTable sourceTable, string newTableName, bool distinct, params string[] columnNames)
{
object[] lastValues;
DataTable newTable;
DataRow[] orderedRows;
if (columnNames == null || columnNames.Length == 0)
throw new ArgumentNullException("columnNames");
lastValues = new object[columnNames.Length];
newTable = new DataTable();

for (int i = 0; i < columnNames.Length; i++)
{
DataColumn column = sourceTable.Columns[columnNames[i]];
if (column == null)
{
throw new ArgumentException(
String.Format("The specified column (columnNames[{0}] with value of '{1}') is not in the sourceTable.", i.ToString(), columnNames[i]),
"columnNames");
}
newTable.Columns.Add(columnNames[i], column.DataType);
}
orderedRows = sourceTable.Select("", string.Join(", ", columnNames));

if (distinct)
{
foreach (DataRow row in orderedRows)
{
if (!ColumnValuesAreEqual(lastValues, row, columnNames))
{
newTable.Rows.Add(CreateRowClone(row, newTable.NewRow(), columnNames));
SetLastValues(lastValues, row, columnNames);
}
}
}
else
{
foreach (DataRow row in orderedRows)
{
newTable.Rows.Add(CreateRowClone(row, newTable.NewRow(), columnNames));
}
}
return newTable;
}
private static bool ColumnValuesAreEqual(object[] lastValues, DataRow currentRow, string[] columnNames)
{
bool areEqual = true;

for (int i = 0; i < columnNames.Length; i++)
{
if (lastValues[i] == null || !lastValues[i].Equals(currentRow[columnNames[i]]))
{
areEqual = false;
break;
}
}
return areEqual;
}
private static DataRow CreateRowClone(DataRow sourceRow, DataRow newRow, string[] columnNames)
{
foreach (string field in columnNames)
{
newRow[field] = sourceRow[field];
}
return newRow;
}
private static void SetLastValues(object[] lastValues, DataRow sourceRow, string[] columnNames)
{
for (int i = 0; i < columnNames.Length; i++)
{
lastValues[i] = sourceRow[columnNames[i]];
}
}
#endregion
说明:由于朋友要求是在 1.1 环境下,所以只有自己写SelectDistinct,只有用DataGrid演示了^_^
源码:
下载
本文介绍了一种在前端程序中实现交叉表的方法,包括读取学生成绩数据、提取不重复的考试时间和科目作为表头,并动态构建交叉表。通过具体代码示例展示了如何使用ADO.NET进行数据处理。
1380

被折叠的 条评论
为什么被折叠?



