交叉表的简单实现2:使用前端程序实现

本文介绍了一种在前端程序中实现交叉表的方法,包括读取学生成绩数据、提取不重复的考试时间和科目作为表头,并动态构建交叉表。通过具体代码示例展示了如何使用ADO.NET进行数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上篇介绍了 交叉表的简单实现1:使用存储过程,这里采取在前端程序实现。
实现要点:
1。读取所有目标成绩(flatScroreTable)
2。从目标成绩中提取考试时间(不重复),作为交叉表的列表头
3。从目标成绩中提取考试科目(不重复),作为交叉表的行表头
4。根据2动态构建一个DataTable(crossScroreTable),此DataTable具有一个科目列,若干考试时间列,以及其他信息。
5。将3中的考试科目写入DataTable
6。从flatScroreTable中读取成绩值填入crossScroreTable对应单元格
说明:便于理解,这里将交叉表crossScroreTable想象成一张Excel表,列名就当作列表头,科目名就当作行表头。

主要代码:
None.gif void  LoadScoreData()
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
ContractedSubBlock.gifExpandedSubBlockStart.gif        
读取指定学生的所有成绩#region 读取指定学生的所有成绩
InBlock.gif        
string stuName = drpStu.SelectedValue;        
InBlock.gif        
string connStr = "SERVER=.;DATABASE=DemoLib;UID=sa";
InBlock.gif        
string sql = "SELECT SubjectName, StudentName, ScoreValue, ExamDate  FROM t_Score WHERE StudentName = @StuName";        
InBlock.gif        DataSet ds 
= new DataSet();        
InBlock.gif        SqlDataAdapter da 
= new SqlDataAdapter(sql, connStr);
InBlock.gif        da.SelectCommand.CommandType 
= CommandType.Text;
InBlock.gif        da.SelectCommand.Parameters.Add(
"@StuName", stuName);           
InBlock.gif        da.Fill(ds, 
"FlatScore");
ExpandedSubBlockEnd.gif        
#endregion
 读取指定学生的所有成绩
InBlock.gif
InBlock.gif        DataTable flatScoreTable 
= ds.Tables[0];
InBlock.gif        DataView flatScoreView 
= new DataView(flatScoreTable);
InBlock.gif        
// 读取科目列表,排除重复
InBlock.gif
        DataTable subjectList;
InBlock.gif        
// .NET 2 using the ToTable method supported by DataView
InBlock.gif        
//subjectList = flatScoreView.ToTable("SubjectList", true, "SubjectName");        
InBlock.gif
        subjectList = SelectDistinct(flatScoreTable, "SubjectList"true"SubjectName");        
InBlock.gif        
// 读取考试时间列表,排除重复
InBlock.gif        
// .NET 2
InBlock.gif
        DataTable examDateList;
InBlock.gif        
// .NET 2 using the ToTable method supported by DataView
InBlock.gif        
//examDateList = flatScoreView.ToTable("ExamDateList", true, "ExamDate");        
InBlock.gif
        examDateList = SelectDistinct(flatScoreTable, "ExamDateList"true"ExamDate");        
InBlock.gif       
ContractedSubBlock.gifExpandedSubBlockStart.gif        
创建 交叉表#region 创建 交叉表
InBlock.gif        DataTable crossScoreTable 
= new DataTable();
InBlock.gif        
ContractedSubBlock.gifExpandedSubBlockStart.gif        
构造表模式#region 构造表模式
InBlock.gif        
// 科目 列
InBlock.gif
        crossScoreTable.Columns.Add("科目"typeof(string));
InBlock.gif        
// 考试时间 列,以时间为列名
ExpandedSubBlockStart.gifContractedSubBlock.gif
        foreach (DataRow r in examDateList.Rows) dot.gif{
InBlock.gif            crossScoreTable.Columns.Add(((DateTime)r[
0]).ToString("yyyy年M月dd日"), typeof(string));
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif        
#endregion
 构造表模式
InBlock.gif        
ContractedSubBlock.gifExpandedSubBlockStart.gif        
从成绩表读取并写入数据#region 从成绩表读取并写入数据        
InBlock.gif        DataColumnCollection cols 
= crossScoreTable.Columns;
InBlock.gif        
// 按先科目(行)后时间(列)遍历        
ExpandedSubBlockStart.gifContractedSubBlock.gif
        foreach (DataRow r in subjectList.Rows)dot.gif{
InBlock.gif            DataRow newRow 
= crossScoreTable.NewRow();
InBlock.gif            
// 科目
InBlock.gif
            newRow[0= r[0];
InBlock.gif            
// 成绩,遍历时间
ExpandedSubBlockStart.gifContractedSubBlock.gif
           for(int i=1; i< cols.Count; i++dot.gif{
InBlock.gif               
// 返回具有指定科目和指定考试的成绩
InBlock.gif               
// eg. "SubjectName='孙光' AND ExamDate='2007-5-19'"
InBlock.gif
               flatScoreView.RowFilter = String.Format("SubjectName='{0}' AND ExamDate='{1}'", r[0], examDateList.Rows[i-1][0]);
ExpandedSubBlockStart.gifContractedSubBlock.gif               
if (flatScoreView.Count > 0dot.gif{
InBlock.gif                   newRow[cols[i]] 
= flatScoreView[0]["ScoreValue"];
ExpandedSubBlockEnd.gif               }

ExpandedSubBlockEnd.gif            }

InBlock.gif            
// 加入新表
InBlock.gif
            crossScoreTable.Rows.Add(newRow);
ExpandedSubBlockEnd.gif        }
        
ExpandedSubBlockEnd.gif        
#endregion
 从成绩表读取并插入数据
InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion
 创建 交叉表
InBlock.gif
InBlock.gif        
// 绑定,输出数据
InBlock.gif
        grdCrossScore.DataSource = crossScoreTable;
InBlock.gif        grdCrossScore.DataBind();
InBlock.gif        grdFlatScore.DataSource 
= flatScoreTable;
InBlock.gif        grdFlatScore.DataBind();
InBlock.gif        grdSubjectList.DataSource 
= subjectList;
InBlock.gif        grdSubjectList.DataBind();
InBlock.gif        grdExamDate.DataSource 
= examDateList;
InBlock.gif        grdExamDate.DataBind();
ExpandedBlockEnd.gif    }

看下这个方法:
None.gif DataTable SelectDistinct(DataTable sourceTable,  string  newTableName,  bool  distinct,  params   string [] columnNames)
扩展 ADO.NET 1.x 中DataTable 以及 DataView 均无法支持的:SELECT DISTINCT Column1,Column2.... 语法,(选择不重复的行)
如果 ADO.NET 2.0 中我们就可以直接使用 DataView 的 ToTable 方法的重载版本:
None.gif public  DataTable ToTable( bool  distinct,  params   string [] columnNames);
None.gif
None.gif
public  DataTable ToTable( string  tableName,  bool  distinct,  params   string [] columnNames);

SelectDistinct 网上有很多版本,原理基本一样,只是效率问题,这里是修改于 Erik Porter 的 Select DISTINCT on DataTable

SelectDistinct完整代码:
ContractedBlock.gif ExpandedBlockStart.gif
ContractedBlock.gifExpandedBlockStart.gifimplements such as 'SELECT DISTINCT Column0, Column1dot.gif' sql clause for DataTable.#region implements such as 'SELECT DISTINCT Column0, Column1dot.gif' sql clause for DataTable. 
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//*
InBlock.gif     * The implement detail refers to 
http://weblogs.asp.net/eporter/archive/2005/02/10/370548.aspx. Many thanks to Erik Porter.
InBlock.gif     * NOTE:The .NET 2.0's DataView provider a ToTable method that will build a DataTable based off of the current DataView and 
InBlock.gif     *      also allow you to specify which columns you want in the DataTable as all as being able to say Distinct rows only.
InBlock.gif     *      So, recommends to consume the override method directly as following:
InBlock.gif     *      <example>
InBlock.gif     *      DataTable srcTable;
InBlock.gif     *      // dot.gif
InBlock.gif     *      DataView srcView = srcTable.DefaultView;
InBlock.gif     *      DataTable dstTable = srcView.ToTable("NewTableName", true, "ColumnName1", "ColumnName2", "ColumnNameN");
InBlock.gif     *      </example>
ExpandedSubBlockEnd.gif    
*/

InBlock.gif
InBlock.gif    
private static DataTable SelectDistinct(DataTable sourceTable, string newTableName, bool distinct, params string[] columnNames)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
object[] lastValues;
InBlock.gif        DataTable newTable;
InBlock.gif        DataRow[] orderedRows;
InBlock.gif
InBlock.gif        
if (columnNames == null || columnNames.Length == 0)
InBlock.gif            
throw new ArgumentNullException("columnNames");
InBlock.gif
InBlock.gif        lastValues 
= new object[columnNames.Length];
InBlock.gif        newTable 
= new DataTable();
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
for (int i = 0; i < columnNames.Length; i++dot.gif{            
InBlock.gif            DataColumn column 
= sourceTable.Columns[columnNames[i]];
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (column == nulldot.gif{
InBlock.gif                
throw new ArgumentException(
InBlock.gif                    String.Format(
"The specified column (columnNames[{0}] with value of '{1}') is not in the sourceTable.", i.ToString(), columnNames[i]),
InBlock.gif                    
"columnNames");
ExpandedSubBlockEnd.gif            }

InBlock.gif            newTable.Columns.Add(columnNames[i], column.DataType);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        orderedRows 
= sourceTable.Select(""string.Join("", columnNames));
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
if (distinct) dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
foreach (DataRow row in orderedRows) dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif                
if (!ColumnValuesAreEqual(lastValues, row, columnNames)) dot.gif{
InBlock.gif                    newTable.Rows.Add(CreateRowClone(row, newTable.NewRow(), columnNames));
InBlock.gif
InBlock.gif                    SetLastValues(lastValues, row, columnNames);
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
else dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
foreach (DataRow row in orderedRows) dot.gif{
InBlock.gif                newTable.Rows.Add(CreateRowClone(row, newTable.NewRow(), columnNames));
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
return newTable;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
private static bool ColumnValuesAreEqual(object[] lastValues, DataRow currentRow, string[] columnNames)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
bool areEqual = true;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
for (int i = 0; i < columnNames.Length; i++dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (lastValues[i] == null || !lastValues[i].Equals(currentRow[columnNames[i]])) dot.gif{
InBlock.gif                areEqual 
= false;
InBlock.gif                
break;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
return areEqual;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
private static DataRow CreateRowClone(DataRow sourceRow, DataRow newRow, string[] columnNames)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
foreach (string field in columnNames) dot.gif{
InBlock.gif            newRow[field] 
= sourceRow[field];
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
return newRow;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
private static void SetLastValues(object[] lastValues, DataRow sourceRow, string[] columnNames)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
for (int i = 0; i < columnNames.Length; i++dot.gif{
InBlock.gif            lastValues[i] 
= sourceRow[columnNames[i]];
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif
ExpandedBlockEnd.gif    
#endregion

说明:由于朋友要求是在 1.1 环境下,所以只有自己写SelectDistinct,只有用DataGrid演示了^_^

源码:
下载
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值