有位朋友要求帮忙实现交叉表(将某些行变为列),之前虽然实现过,但没有整理,今天顺便整理一下,便于自己以后参考,希望对其他网友有帮助,欢迎指出不足之处^_^

数据库中原始数据类似:
交叉表的简单实现1:使用存储过程
要求前台显示为:
交叉表的简单实现1:使用存储过程

建立表结构:

交叉表的简单实现1:使用存储过程CREATE TABLE [dbo].[t_Score] (
交叉表的简单实现1:使用存储过程    
[ScoreId] [int] IDENTITY (11NOT NULL ,
交叉表的简单实现1:使用存储过程    
[SubjectName] [varchar] (50NOT NULL ,
交叉表的简单实现1:使用存储过程    
[StudentName] [varchar] (10NOT NULL ,
交叉表的简单实现1:使用存储过程    
[ScoreValue] [real] NOT NULL ,
交叉表的简单实现1:使用存储过程    
[ExamDate] [datetime] NOT NULL 
交叉表的简单实现1:使用存储过程)

样本数据

交叉表的简单实现1:使用存储过程INSERT INTO t_Score(SubjectName, StudentName, ScoreValue, ExamDate)
交叉表的简单实现1:使用存储过程
VALUES('C语言''孙光'80'2006-01-05')
交叉表的简单实现1:使用存储过程
交叉表的简单实现1:使用存储过程
INSERT INTO t_Score(SubjectName, StudentName, ScoreValue, ExamDate)
交叉表的简单实现1:使用存储过程
VALUES('日语''孙光'79'2006-07-06')
交叉表的简单实现1:使用存储过程
交叉表的简单实现1:使用存储过程
INSERT INTO t_Score(SubjectName, StudentName, ScoreValue, ExamDate)
交叉表的简单实现1:使用存储过程
VALUES('C语言''孙光'89'2006-08-09')
交叉表的简单实现1:使用存储过程
交叉表的简单实现1:使用存储过程
INSERT INTO t_Score(SubjectName, StudentName, ScoreValue, ExamDate)
交叉表的简单实现1:使用存储过程
VALUES('英语''王二'77'2006-09-10')
交叉表的简单实现1:使用存储过程
交叉表的简单实现1:使用存储过程
INSERT INTO t_Score(SubjectName, StudentName, ScoreValue, ExamDate)
交叉表的简单实现1:使用存储过程
VALUES('英语''孙光'77'2006-07-06')
交叉表的简单实现1:使用存储过程
交叉表的简单实现1:使用存储过程
INSERT INTO t_Score(SubjectName, StudentName, ScoreValue, ExamDate)
交叉表的简单实现1:使用存储过程
VALUES('C语言''王二'89'2006-08-09')


1。通过存储过程实现
实现要点:
a. 使用一个临时表(#ScoreTbl)存储指定学生的所有成绩(根据实际情况,可能有更多条件)
说明:这里无法使用表变量,因为表变量无法用于动态SQL语句中。

b.临时表#ScoreTbl中使用一个平均值标志位,因为将每个科目的平均值计算出来之后也存入了#ScoreTbl
当然,根据需求,还可以增加总成绩标志位等等

c.使用递归的SELECT语句创建动态 DateExam(考试时间)列(参考:Paul Nielsen 的 Microsoft SQL Server 2000宝典 P353 12-7 递归的Select变量)
注意:这里递归成的 @sql  语句有个潜在的bug,就是@sql长度必须小于8000个字符(如果使用sq_executeSql执行动态语句,必须声名为nvarchar,则只能使用4000个字符)
邹建大哥的 化解字符串不能超过8000的方法及交叉表的处理 讨论了三种可选择的方案。
本示例不做此讨论,只求实现交叉表^_^

d.使用CASE表达式选择 DateExam 对应的 ScoreValue(成绩值)(参考:Paul Nielsen 的 Microsoft SQL Server 2000宝典 P353 12-7 -2 动态交叉表查询)

e.使用聚合函数(这里使用SUM)包含ScoreValue列,因为ScoreValue未出现在GROUP BY子句中


具体实现:

交叉表的简单实现1:使用存储过程ALTER PROC usp_GetCrossScore4(
交叉表的简单实现1:使用存储过程
@StuName varchar(10)
交叉表的简单实现1:使用存储过程)
交叉表的简单实现1:使用存储过程
AS
交叉表的简单实现1:使用存储过程
-- creates a temp table to hold the score records
交叉表的简单实现1:使用存储过程
CREATE TABLE #ScoreTbl(
交叉表的简单实现1:使用存储过程ScoreId 
int,
交叉表的简单实现1:使用存储过程SubjectName 
varchar(50),
交叉表的简单实现1:使用存储过程StudentName 
varchar(10),
交叉表的简单实现1:使用存储过程ScoreValue 
real,
交叉表的简单实现1:使用存储过程ExamDate 
datetime,
交叉表的简单实现1:使用存储过程AvgFlag 
bit DEFAULT(0)    -- marks as the average of some subject
交叉表的简单实现1:使用存储过程
)
交叉表的简单实现1:使用存储过程
-- populates basic data of some student
交叉表的简单实现1:使用存储过程
INSERT INTO #ScoreTbl(ScoreId, SubjectName, StudentName, ScoreValue, ExamDate)
交叉表的简单实现1:使用存储过程
SELECT ScoreId, SubjectName, StudentName, ScoreValue, ExamDate FROM t_Score s WHERE s.StudentName = @StuName
交叉表的简单实现1:使用存储过程
-- calculates total for per subject and appends to the temp table
交叉表的简单实现1:使用存储过程
INSERT INTO #ScoreTbl(ScoreId, SubjectName, StudentName, ScoreValue, ExamDate, AvgFlag)
交叉表的简单实现1:使用存储过程
SELECT NULL, SubjectName, StudentName, AVG(ScoreValue), NULL1 FROM #ScoreTbl s GROUP BY SubjectName, StudentName
交叉表的简单实现1:使用存储过程
--SELECT * FROM #ScoreTbl
交叉表的简单实现1:使用存储过程

交叉表的简单实现1:使用存储过程
DECLARE @Sql varchar(8000)
交叉表的简单实现1:使用存储过程
-- NOTE: some known bug -> you make sure the length of the dynamical sql is less than 8000.
交叉表的简单实现1:使用存储过程--
    fortunately, Mr Zou have made a deep discussion againt it at http://blog.csdn.net/zjcxc/archive/2003/12/29/20075.aspx.
交叉表的简单实现1:使用存储过程
SET @Sql = 'SELECT SubjectName 科目'
交叉表的简单实现1:使用存储过程
SELECT @sql = @sql + ', SUM(CASE ExamDate WHEN ''' + CONVERT(varchar(20), ExamDate, 102+ ''' THEN ScoreValue ELSE NULL END)''' + CAST(YEAR(ExamDate) AS VARCHAR+ '' + CAST(MONTH(ExamDate) AS VARCHAR+ '' + CAST(DAY(ExamDate) AS VARCHAR+ ''''
交叉表的简单实现1:使用存储过程
FROM (SELECT DISTINCT ExamDate FROM t_Score s WHERE s.StudentName = @StuName) ss
交叉表的简单实现1:使用存储过程
SET @Sql = @Sql + ', SUM(CASE AvgFlag WHEN 1 THEN ScoreValue ELSE NULL END) ''平均分'''
交叉表的简单实现1:使用存储过程
--PRINT @Sql
交叉表的简单实现1:使用存储过程--
 runs the dynamical sql statement
交叉表的简单实现1:使用存储过程
EXEC(@sql+' FROM #ScoreTbl s GROUP BY SubjectName')
交叉表的简单实现1:使用存储过程
ALTER PROC usp_GetCrossScore4(
交叉表的简单实现1:使用存储过程
@StuName varchar(10)
交叉表的简单实现1:使用存储过程)
交叉表的简单实现1:使用存储过程
AS
交叉表的简单实现1:使用存储过程
-- creates a temp table to hold the score records
交叉表的简单实现1:使用存储过程
CREATE TABLE #ScoreTbl(
交叉表的简单实现1:使用存储过程ScoreId 
int,
交叉表的简单实现1:使用存储过程SubjectName 
varchar(50),
交叉表的简单实现1:使用存储过程StudentName 
varchar(10),
交叉表的简单实现1:使用存储过程ScoreValue 
real,
交叉表的简单实现1:使用存储过程ExamDate 
datetime,
交叉表的简单实现1:使用存储过程AvgFlag 
bit DEFAULT(0)    -- marks as the average of some subject
交叉表的简单实现1:使用存储过程
)
交叉表的简单实现1:使用存储过程
-- populates basic data of some student
交叉表的简单实现1:使用存储过程
INSERT INTO #ScoreTbl(ScoreId, SubjectName, StudentName, ScoreValue, ExamDate)
交叉表的简单实现1:使用存储过程
SELECT ScoreId, SubjectName, StudentName, ScoreValue, ExamDate FROM t_Score s WHERE s.StudentName = @StuName
交叉表的简单实现1:使用存储过程
-- calculates total for per subject and appends to the temp table
交叉表的简单实现1:使用存储过程
INSERT INTO #ScoreTbl(ScoreId, SubjectName, StudentName, ScoreValue, ExamDate, AvgFlag)
交叉表的简单实现1:使用存储过程
SELECT NULL, SubjectName, StudentName, AVG(ScoreValue), NULL1 FROM #ScoreTbl s GROUP BY SubjectName, StudentName
交叉表的简单实现1:使用存储过程
--SELECT * FROM #ScoreTbl
交叉表的简单实现1:使用存储过程

交叉表的简单实现1:使用存储过程
DECLARE @Sql varchar(8000)
交叉表的简单实现1:使用存储过程
-- NOTE: some known bug -> you make sure the length of the dynamical sql is less than 8000.
交叉表的简单实现1:使用存储过程--
    fortunately, Mr Zou have made a deep discussion againt it at http://blog.csdn.net/zjcxc/archive/2003/12/29/20075.aspx.
交叉表的简单实现1:使用存储过程
SET @Sql = 'SELECT SubjectName 科目'
交叉表的简单实现1:使用存储过程
SELECT @sql = @sql + ', SUM(CASE ExamDate WHEN ''' + CONVERT(varchar(20), ExamDate, 102+ ''' THEN ScoreValue ELSE NULL END)''' + CAST(YEAR(ExamDate) AS VARCHAR+ '' + CAST(MONTH(ExamDate) AS VARCHAR+ '' + CAST(DAY(ExamDate) AS VARCHAR+ ''''
交叉表的简单实现1:使用存储过程
FROM (SELECT DISTINCT ExamDate FROM t_Score s WHERE s.StudentName = @StuName) ss
交叉表的简单实现1:使用存储过程
SET @Sql = @Sql + ', SUM(CASE AvgFlag WHEN 1 THEN ScoreValue ELSE NULL END) ''平均分'''
交叉表的简单实现1:使用存储过程
--PRINT @Sql
交叉表的简单实现1:使用存储过程--
 runs the dynamical sql statement
交叉表的简单实现1:使用存储过程
EXEC(@sql+' FROM #ScoreTbl s GROUP BY SubjectName')

测试代码:

>

效果:
交叉表的简单实现1:使用存储过程

源码:
下载

 下篇介绍如何使用程序动态构造交叉表。
交叉表的简单实现2:使用前端程序实现

相关文章:

  • 2021-10-31
  • 2021-08-02
  • 2022-12-23
  • 2021-08-31
  • 2021-10-08
  • 2022-12-23
  • 2022-12-23
  • 2021-12-20
猜你喜欢
  • 2021-12-31
  • 2021-09-05
  • 2022-12-23
  • 2022-01-02
  • 2022-03-08
相关资源
相似解决方案