学生分班SQL实现

/*
某中学有2个重点班18个普通班
要求:
1.重点班人数占总人数的20%
2.平均分越接近越好,性别比越接近越好
3.尽量不要出现班级同名的情况
*/

--用到的表
CREATE TABLE [dbo].[NBAC_dbo_Scores]
(
	[student] [varchar](50) NULL,
	[subject] [varchar](50) NULL,
	[score] [numeric](18, 1) NULL
) ON [PRIMARY]
go

CREATE TABLE [dbo].[NBAC_dbo_Students]
(
	[stuno] [float] NULL,
	[stuname] [nvarchar](255) NULL,
	[sex] [nvarchar](255) NULL
) ON [PRIMARY]
GO
--数据

--计算普通班和重点班
SELECT a.student,stuname,a.zcj,b.sex ,
CASE when 100.0*ROW_NUMBER() OVER(ORDER BY a.zcj)/COUNT(1) OVER() >=COUNT(1) OVER()/20.0 *2 THEN '重点' ELSE '普通' END 类型 ,CONVERT(int,null) AS 班级
INTO #tmp
FROM 
(
  SELECT student,SUM(score) AS zcj FROM dbo.NBAC_dbo_Scores GROUP BY student
)  
a INNER JOIN  dbo.NBAC_dbo_Students b ON a.student = b.stuno 
 

--故意设置重名数据
UPDATE  #tmp SET stuname='小马' WHERE student='201818039'--赖银兵
UPDATE  #tmp SET stuname='小马' WHERE student='201801016'--姜效文
UPDATE  #tmp SET stuname='小马' WHERE student='201807007'--王涛
UPDATE  #tmp SET stuname='小马' WHERE student='201818033'--刘兴鑫
UPDATE  #tmp SET stuname='小马' WHERE student='201801020'--曾传慧

--创建班级临时表
CREATE TABLE #ban
(
	number INT,
	isFen BIT
)


DECLARE @banj INT 
DECLARE @student VARCHAR(10)

--普通班
SET @banj=0
SET @student=''

INSERT INTO #ban(number,isFen)
SELECT number,0  FROM master..spt_values WHERE type='P' AND number BETWEEN 1 AND 18 
 
WHILE 1=1
BEGIN 
	SELECT TOP 1 @banj=number FROM #ban a  WHERE isFen=0 ORDER BY (SELECT AVG(zcj) FROM #tmp WHERE 班级=a.number) desc
	UPDATE #ban SET isFen=1 WHERE number=@banj
	SELECT TOP 1 @student=a.student FROM #tmp  a WHERE 类型='普通' AND 班级 IS NULL AND NOT EXISTS(SELECT 1 FROM #tmp WHERE 班级=@banj AND stuname=a.stuname) 
	ORDER BY sex,zcj
	 
	IF @student=''
	SELECT TOP 1 @student=a.student FROM #tmp  a WHERE 类型='普通' AND 班级 IS NULL  
	ORDER BY sex,zcj
	
	IF @student=''
		BREAK
	UPDATE #tmp SET 班级=@banj WHERE student=@student
	
	SET @student=''
	
	IF NOT EXISTS(SELECT 1 FROM #ban WHERE isFen=0 ) 
	BEGIN 
		UPDATE #ban SET isFen=0
	END 	
END 

--重点班
SET @banj=0 
SET @student=''

TRUNCATE TABLE #ban
INSERT INTO #ban(number,isFen)
SELECT number,0  FROM master..spt_values WHERE type='P' AND number BETWEEN 1 AND 2 

WHILE 1=1
BEGIN 
	SELECT TOP 1 @banj=number FROM #ban a  WHERE isFen=0 ORDER BY (SELECT AVG(zcj) FROM #tmp WHERE 班级=a.number) desc
	UPDATE #ban SET isFen=1 WHERE number=@banj
	
	SELECT TOP 1 @student=a.student FROM #tmp  a WHERE 类型='重点' AND 班级 IS NULL AND NOT EXISTS(SELECT 1 FROM #tmp WHERE 班级=@banj AND stuname=a.stuname) 
	ORDER BY sex,zcj
	IF @student=''
	SELECT TOP 1 @student=a.student FROM #tmp  a WHERE 类型='重点' AND 班级 IS NULL 
	ORDER BY sex,zcj
	
	IF @student=''
		BREAK
	UPDATE #tmp SET 班级=@banj WHERE student=@student
	
	SET @student=''
	 
	IF NOT EXISTS(SELECT 1 FROM #ban WHERE isFen=0 ) 
	BEGIN
		UPDATE #ban SET isFen=0
	END 
	 
END 

 
--调整普通班,平均分误差设置0.1,最大调整次数10000
DECLARE @banj1 INT
DECLARE @banj2 INT
DECLARE @pjf1 NUMERIC(18,6)
DECLARE @pjf2 NUMERIC(18,6)
DECLARE @stu1 VARCHAR(10)
DECLARE @stu2 VARCHAR(10)
DECLARE @xb VARCHAR(10)
DECLARE @zcj NUMERIC(18,6)
DECLARE @xm1 VARCHAR(10)
DECLARE @xm2 VARCHAR(10)
DECLARE @i INT 
DECLARE @jd NUMERIC(18,6)=0.1


SET @pjf1 =1
SET @pjf2 =0
SET @i = 0

WHILE  ABS(@pjf1-@pjf2)>=@jd AND @i<10000
BEGIN 
	SET @stu1=''
	SET @stu2=''
	SELECT TOP 1 @banj1=班级,@pjf1=AVG(zcj) FROM #tmp WHERE 类型='普通' GROUP BY 班级 ORDER BY 2
	SELECT TOP 1 @banj2=班级,@pjf2=AVG(zcj) FROM #tmp WHERE 类型='普通' GROUP BY 班级 ORDER BY 2 DESC
	
	SELECT @stu1=student,@xb=sex,@zcj=zcj,@xm1=stuname FROM #tmp WHERE 班级=@banj1 AND  类型='普通' ORDER BY  NEWID()
	SELECT @stu2=student,@xm2=stuname FROM #tmp WHERE 班级=@banj2 AND sex=@xb AND zcj>@zcj  AND  类型='普通' ORDER BY NEWID()
 
	IF @stu1<>'' AND @stu2<>'' 
	BEGIN 
		IF NOT EXISTS(SELECT 1 FROM #tmp WHERE 班级=@banj1 AND stuname=@xm2) AND NOT EXISTS(SELECT 1 FROM #tmp WHERE 班级=@banj2 AND stuname=@xm1)
		BEGIN  
			UPDATE #tmp SET 班级=@banj2 WHERE student=@stu1
			UPDATE #tmp SET 班级=@banj1 WHERE student=@stu2
		END 
	END 
	
	
	SELECT TOP 1 @pjf1=AVG(zcj) FROM #tmp WHERE 类型='普通' AND 班级 NOT IN(@pjf1,@pjf2) GROUP BY 班级 ORDER BY 1
	SELECT TOP 1 @pjf2=AVG(zcj) FROM #tmp WHERE 类型='普通' AND 班级 NOT IN(@pjf1,@pjf2) GROUP BY 班级 ORDER BY 1 DESC
 
	SET @i=@i+1
END 

--调整重点班
SET  @pjf1 =1
SET @pjf2 =0
SET @i = 0
WHILE  ABS(@pjf1-@pjf2)>=@jd AND @i<10000
BEGIN 
	SET @stu1=''
	SET @stu2=''
	SELECT TOP 1 @banj1=班级,@pjf1=AVG(zcj) FROM #tmp WHERE 类型='重点' GROUP BY 班级 ORDER BY 2
	SELECT TOP 1 @banj2=班级,@pjf2=AVG(zcj) FROM #tmp WHERE 类型='重点' GROUP BY 班级 ORDER BY 2 DESC
	
	SELECT @stu1=student,@xb=sex,@zcj=zcj,@xm1=stuname FROM #tmp WHERE 班级=@banj1 AND  类型='重点' ORDER BY  NEWID()
	SELECT @stu2=student,@xm2=stuname FROM #tmp WHERE 班级=@banj2 AND sex=@xb AND zcj>@zcj AND  类型='重点' ORDER BY NEWID()
 
	IF @stu1<>'' AND @stu2<>'' 
	BEGIN 
		IF NOT EXISTS(SELECT 1 FROM #tmp WHERE 班级=@banj1 AND stuname=@xm2) AND NOT EXISTS(SELECT 1 FROM #tmp WHERE 班级=@banj2 AND stuname=@xm1)
		BEGIN  
			UPDATE #tmp SET 班级=@banj2 WHERE student=@stu1
			UPDATE #tmp SET 班级=@banj1 WHERE student=@stu2
		END 
	END 
	
	
	SELECT TOP 1 @pjf1=AVG(zcj) FROM #tmp WHERE 类型='重点' AND 班级 NOT IN(@pjf1,@pjf2) GROUP BY 班级 ORDER BY 1
	SELECT TOP 1 @pjf2=AVG(zcj) FROM #tmp WHERE 类型='重点' AND 班级 NOT IN(@pjf1,@pjf2) GROUP BY 班级 ORDER BY 1 DESC
 
	SET @i=@i+1
END 
 
 
--统计结果
SELECT 班级,AVG(zcj) AS 平均分 FROM #tmp WHERE 类型='普通' GROUP BY 班级 ORDER BY 2
SELECT 班级,SUM(IIF(sex='男',1,0)) AS 男,SUM(IIF(sex='男' ,0,1)) AS 女,COUNT(1) AS 总人数 FROM #tmp WHERE 类型='普通' GROUP BY 班级 ORDER BY 班级

SELECT 班级,AVG(zcj) AS 平均分 FROM #tmp WHERE 类型='重点' GROUP BY 班级 ORDER BY 班级
SELECT 班级,SUM(IIF(sex='男',1,0)) AS 男,SUM(IIF(sex='男' ,0,1)) AS 女,COUNT(1) AS 总人数 FROM #tmp WHERE 类型='重点' GROUP BY 班级 ORDER BY 班级

SELECT 班级,stuname,COUNT(1) AS 人数  FROM #tmp  WHERE 类型='重点'   GROUP BY 班级,stuname HAVING COUNT(1)>1
SELECT 班级,stuname,COUNT(1) AS 人数  FROM #tmp  WHERE 类型='普通'   GROUP BY 班级,stuname HAVING COUNT(1)>1


DROP TABLE #tmp 
DROP TABLE #ban 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值