EsaProcessingService.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. using YBEE.EQM.Core;
  2. namespace YBEE.EQM.Application;
  3. /// <summary>
  4. /// 有效分分析处理服务
  5. /// </summary>
  6. public class EsaProcessingService(IRepository<EsaPlan> rep) : IEsaProcessingService, ITransient
  7. {
  8. /// <summary>
  9. /// 分析处理
  10. /// </summary>
  11. /// <param name="esaPlanId"></param>
  12. /// <returns></returns>
  13. public async Task Execute(int esaPlanId)
  14. {
  15. var plan = await rep.DetachedEntities
  16. .Include(t => t.EsaBaseLines).ThenInclude(t => t.EsaBaseLineCourses)
  17. .FirstOrDefaultAsync(t => t.Id == esaPlanId)
  18. ?? throw Oops.Oh(ErrorCode.E2001);
  19. // 更新状态
  20. await rep.SqlNonQueryAsync($"UPDATE esa_plan SET status = {(short)ProcessingStatus.RUNNING} WHERE id = {esaPlanId}");
  21. try
  22. {
  23. foreach (var esaBaseLine in plan.EsaBaseLines)
  24. {
  25. try
  26. {
  27. // 更新状态
  28. await rep.SqlNonQueryAsync($"UPDATE esa_base_line SET status = {(short)ProcessingStatus.RUNNING} WHERE id = {esaBaseLine.Id}");
  29. // 构造分析学科
  30. var courseIds = string.Join(", ", esaBaseLine.EsaBaseLineCourses.OrderBy(t => t.CourseId).Select(t => t.CourseId));
  31. // 构造取数条件
  32. var whereBaseSql = $"WHERE T1.exam_plan_id = {plan.ExamPlanId} AND exam_sample_type = 1 AND T1.grade_id = {esaBaseLine.GradeId} AND T1.is_excluded = 0 AND T1.score > 0";
  33. var whereSql = $"{whereBaseSql} AND T1.course_id IN ({courseIds})";
  34. // 删除数据
  35. var deleteWhereSql = $"WHERE esa_plan_id = {esaPlanId} AND esa_base_line_id = {esaBaseLine.Id} AND grade_id = {esaBaseLine.GradeId}";
  36. await rep.SqlNonQueryAsync(@$"
  37. DELETE FROM esa_line_total {deleteWhereSql};
  38. DELETE FROM esa_line_course {deleteWhereSql};
  39. DELETE FROM esa_line_course_score {deleteWhereSql};
  40. ");
  41. #region 区级分析
  42. #region 总分上线
  43. // 总分上线分
  44. var totalLineScore = await rep.SqlScalarAsync<decimal>(@$"
  45. SELECT MIN(T1.total_score) AS line_score
  46. FROM
  47. (
  48. SELECT total_score
  49. FROM
  50. (
  51. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  52. FROM exam_score AS T1
  53. {whereSql}
  54. GROUP BY T1.exam_student_id
  55. ) AS T1
  56. ORDER BY T1.total_score DESC
  57. LIMIT {esaBaseLine.LineCount}
  58. ) AS T1;
  59. ");
  60. // 总分上线均分
  61. var totalLineAvgScore = Math.Round(await rep.SqlScalarAsync<decimal>(@$"
  62. SELECT AVG(T1.total_score) AS line_avg_score
  63. FROM
  64. (
  65. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  66. FROM exam_score AS T1
  67. {whereSql}
  68. GROUP BY T1.exam_student_id
  69. ) AS T1
  70. WHERE T1.total_score >= {totalLineScore};
  71. "), 2);
  72. // 更新有效系数
  73. var factor = Math.Round(totalLineScore / totalLineAvgScore, 8);
  74. await rep.SqlNonQueryAsync($"UPDATE esa_base_line SET line_score = {totalLineScore}, factor = {factor} WHERE id = {esaBaseLine.Id}");
  75. // 实际上线人数
  76. var factLineCount = await rep.SqlScalarAsync($@"
  77. SELECT COUNT(1) AS line_count
  78. FROM
  79. (
  80. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  81. FROM exam_score AS T1
  82. {whereSql}
  83. GROUP BY T1.exam_student_id
  84. ) AS T1
  85. WHERE T1.total_score >= {totalLineScore};
  86. ");
  87. // 总均分
  88. var totalAvgScore = Math.Round(await rep.SqlScalarAsync<decimal>(@$"
  89. SELECT AVG(total_score) AS avg_score
  90. FROM
  91. (
  92. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  93. FROM exam_score AS T1
  94. {whereSql}
  95. GROUP BY T1.exam_student_id
  96. ) AS T1;
  97. "), 2);
  98. // 学科有效分
  99. var totalRelativeDiff = Math.Round((totalLineScore - totalAvgScore) / totalLineScore, 8);
  100. await rep.SqlNonQueryAsync(@$"
  101. -- 总分
  102. INSERT INTO esa_line_course_score(esa_level, esa_line_level, esa_plan_id, esa_base_line_id, grade_id, course_id, avg_score, line_avg_score, line_score, relative_diff)
  103. VALUES({(short)EsaLevel.DISTRICT}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {esaBaseLine.GradeId}, {(short)MultCourse.TOTAL}, {totalAvgScore}, {totalLineAvgScore}, {totalLineScore}, {totalRelativeDiff});
  104. -- 单科
  105. INSERT INTO esa_line_course_score(esa_level, esa_line_level, esa_plan_id, esa_base_line_id, grade_id, course_id, avg_score, line_avg_score, line_score, relative_diff)
  106. SELECT {(short)EsaLevel.DISTRICT}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {esaBaseLine.GradeId}, T1.course_id, T2.avg_course_score, T1.avg_line_course_score, T1.course_line_score, ROUND((T1.course_line_score - T2.avg_course_score) / T1.course_line_score, 8) AS relative_diff
  107. FROM
  108. (
  109. SELECT T1.course_id, ROUND(AVG(T1.score), 2) AS avg_line_course_score, ROUND(ROUND(AVG(T1.score), 2) * {factor}, 2) AS course_line_score
  110. FROM
  111. (
  112. SELECT T1.exam_student_id, T1.course_id, T1.score
  113. FROM exam_score AS T1
  114. {whereSql}
  115. ) AS T1
  116. JOIN
  117. (
  118. SELECT T1.exam_student_id
  119. FROM
  120. (
  121. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  122. FROM exam_score AS T1
  123. {whereSql}
  124. GROUP BY T1.exam_student_id
  125. ) AS T1
  126. WHERE T1.total_score >= {totalLineScore}
  127. ) AS T2 ON T1.exam_student_id = T2.exam_student_id
  128. GROUP BY T1.course_id
  129. ) AS T1
  130. JOIN
  131. (
  132. SELECT T1.course_id, ROUND(AVG(T1.score), 2) AS avg_course_score
  133. FROM exam_score AS T1
  134. {whereSql}
  135. GROUP BY T1.course_id
  136. ) AS T2 ON T1.course_id = T2.course_id;
  137. ");
  138. //// TODO: 临时终止
  139. //continue;
  140. // 全区
  141. await rep.SqlNonQueryAsync(@$"
  142. INSERT INTO esa_line_total(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, grade_id, line_count, total_count, line_rate, factor)
  143. SELECT {(short)EsaLevel.DISTRICT}, {(short)EsaDataScopeType.TOTAL}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {esaBaseLine.GradeId}, COUNT(1) AS line_count, T2.total_count, COUNT(1) / T2.total_count, 0
  144. FROM
  145. (
  146. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  147. FROM exam_score AS T1
  148. {whereSql}
  149. GROUP BY T1.exam_student_id
  150. ) AS T1
  151. JOIN
  152. (
  153. SELECT COUNT(1) as total_count
  154. FROM
  155. (
  156. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  157. FROM exam_score AS T1
  158. {whereSql}
  159. GROUP BY T1.exam_student_id
  160. ) AS T1
  161. ) AS T2 ON 1 = 1
  162. WHERE T1.total_score >= {totalLineScore};
  163. ");
  164. // 学校
  165. await rep.SqlNonQueryAsync(@$"
  166. INSERT INTO esa_line_total(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, grade_id, sys_org_id, line_count, total_count, line_rate, factor)
  167. SELECT {(short)EsaLevel.DISTRICT}, {(short)EsaDataScopeType.ORG}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {esaBaseLine.GradeId}, T1.sys_org_id, COUNT(1) AS line_count, T2.total_count, COUNT(1) / T2.total_count, 0
  168. FROM
  169. (
  170. SELECT T1.sys_org_id, T1.exam_student_id, SUM(T1.score) AS total_score
  171. FROM exam_score AS T1
  172. {whereSql}
  173. GROUP BY T1.sys_org_id, T1.exam_student_id
  174. ) AS T1
  175. JOIN
  176. (
  177. SELECT T1.sys_org_id, COUNT(1) as total_count
  178. FROM
  179. (
  180. SELECT T1.sys_org_id, T1.exam_student_id, SUM(T1.score) AS total_score
  181. FROM exam_score AS T1
  182. {whereSql}
  183. GROUP BY T1.sys_org_id, T1.exam_student_id
  184. ) AS T1
  185. GROUP BY T1.sys_org_id
  186. ) AS T2 ON T1.sys_org_id = T2.sys_org_id
  187. WHERE T1.total_score >= {totalLineScore}
  188. GROUP BY T1.sys_org_id;
  189. ");
  190. // 班级
  191. await rep.SqlNonQueryAsync(@$"
  192. INSERT INTO esa_line_total(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, grade_id, sys_org_id, school_class_id, class_number, line_count, total_count, line_rate, factor)
  193. SELECT {(short)EsaLevel.DISTRICT}, {(short)EsaDataScopeType.CLASS}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {esaBaseLine.GradeId}, T1.sys_org_id, T1.school_class_id, T1.class_number, COUNT(1) AS line_count, T2.total_count, COUNT(1) / T2.total_count, 0
  194. FROM
  195. (
  196. SELECT T1.sys_org_id, T1.school_class_id, T1.class_number, T1.exam_student_id, SUM(T1.score) AS total_score
  197. FROM exam_score AS T1
  198. {whereSql}
  199. GROUP BY T1.sys_org_id, T1.school_class_id, T1.class_number, T1.exam_student_id
  200. ) AS T1
  201. JOIN
  202. (
  203. SELECT T1.sys_org_id, T1.school_class_id, T1.class_number, COUNT(1) as total_count
  204. FROM
  205. (
  206. SELECT T1.sys_org_id, T1.school_class_id, T1.class_number, T1.exam_student_id, SUM(T1.score) AS total_score
  207. FROM exam_score AS T1
  208. {whereSql}
  209. GROUP BY T1.sys_org_id, T1.school_class_id, T1.class_number, T1.exam_student_id
  210. ) AS T1
  211. GROUP BY T1.sys_org_id, T1.school_class_id, T1.class_number
  212. ) AS T2 ON T1.sys_org_id = T2.sys_org_id AND T1.school_class_id = T2.school_class_id AND T1.class_number = T2.class_number
  213. WHERE T1.total_score >= {totalLineScore}
  214. GROUP BY T1.sys_org_id, T1.school_class_id, T1.class_number;
  215. ");
  216. #endregion
  217. #region 学科上线
  218. var courseLines = await rep.Change<EsaLineCourseScore>()
  219. .DetachedEntities
  220. .Where(t => t.EsaPlanId == esaPlanId &&
  221. t.EsaBaseLineId == esaBaseLine.Id &&
  222. t.EsaLevel == EsaLevel.DISTRICT &&
  223. t.EsaLineLevel == esaBaseLine.EsaLineLevel &&
  224. t.GradeId == esaBaseLine.GradeId &&
  225. t.CourseId != (short)MultCourse.TOTAL
  226. ).ToListAsync();
  227. foreach (var courseLine in courseLines)
  228. {
  229. // 单科条件
  230. var courseWhereSql = $"{whereBaseSql} AND T1.course_id = {courseLine.CourseId}";
  231. // 全区 - 单上线
  232. await rep.SqlNonQueryAsync(@$"
  233. INSERT INTO esa_line_course(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, course_id, grade_id, line_count, total_count, line_rate, is_double_line)
  234. SELECT {(short)EsaLevel.DISTRICT}, {(short)EsaDataScopeType.TOTAL}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {courseLine.CourseId}, {esaBaseLine.GradeId}, T1.line_count, T2.total_count, T1.line_count / T2.total_count, 0
  235. FROM
  236. (
  237. SELECT COUNT(1) AS line_count
  238. FROM exam_score AS T1
  239. {courseWhereSql} AND T1.score >= {courseLine.LineScore}
  240. ) AS T1
  241. JOIN
  242. (
  243. SELECT COUNT(1) as total_count
  244. FROM exam_score AS T1
  245. {courseWhereSql}
  246. ) AS T2 ON 1 = 1;
  247. ");
  248. // 全区 - 双上线
  249. await rep.SqlNonQueryAsync(@$"
  250. INSERT INTO esa_line_course(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, course_id, grade_id, line_count, total_count, line_rate, is_double_line)
  251. SELECT {(short)EsaLevel.DISTRICT}, {(short)EsaDataScopeType.TOTAL}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {courseLine.CourseId}, {esaBaseLine.GradeId}, T1.line_count, T2.total_count, T1.line_count / T2.total_count, 1
  252. FROM
  253. (
  254. SELECT COUNT(1) AS line_count
  255. FROM
  256. (
  257. SELECT T1.exam_student_id, T1.score
  258. FROM exam_score AS T1
  259. {courseWhereSql}
  260. ) AS T1
  261. JOIN
  262. (
  263. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  264. FROM exam_score AS T1
  265. {whereSql}
  266. GROUP BY T1.exam_student_id
  267. ) AS T2 ON T1.exam_student_id = T2.exam_student_id
  268. WHERE T1.score >= {courseLine.LineScore} AND T2.total_score >= {totalLineScore}
  269. ) AS T1
  270. JOIN
  271. (
  272. SELECT COUNT(1) as total_count
  273. FROM exam_score AS T1
  274. {courseWhereSql}
  275. ) AS T2 ON 1 = 1;
  276. ");
  277. // 学校 - 单上线
  278. await rep.SqlNonQueryAsync(@$"
  279. INSERT INTO esa_line_course(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, course_id, grade_id, sys_org_id, line_count, total_count, line_rate, is_double_line)
  280. SELECT {(short)EsaLevel.DISTRICT}, {(short)EsaDataScopeType.ORG}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {courseLine.CourseId}, {esaBaseLine.GradeId}, T1.sys_org_id, T1.line_count, T2.total_count, T1.line_count / T2.total_count, 0
  281. FROM
  282. (
  283. SELECT T1.sys_org_id, COUNT(1) AS line_count
  284. FROM exam_score AS T1
  285. {courseWhereSql} AND T1.score >= {courseLine.LineScore}
  286. GROUP BY T1.sys_org_id
  287. ) AS T1
  288. JOIN
  289. (
  290. SELECT T1.sys_org_id, COUNT(1) as total_count
  291. FROM exam_score AS T1
  292. {courseWhereSql}
  293. GROUP BY T1.sys_org_id
  294. ) AS T2 ON T1.sys_org_id = T2.sys_org_id;
  295. ");
  296. // 学校 - 双上线
  297. await rep.SqlNonQueryAsync(@$"
  298. INSERT INTO esa_line_course(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, course_id, grade_id, sys_org_id, line_count, total_count, line_rate, is_double_line)
  299. SELECT {(short)EsaLevel.DISTRICT}, {(short)EsaDataScopeType.ORG}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {courseLine.CourseId}, {esaBaseLine.GradeId}, T1.sys_org_id, T1.line_count, T2.total_count, T1.line_count / T2.total_count, 1
  300. FROM
  301. (
  302. SELECT T1.sys_org_id, COUNT(1) AS line_count
  303. FROM
  304. (
  305. SELECT T1.sys_org_id, T1.exam_student_id, T1.score
  306. FROM exam_score AS T1
  307. {courseWhereSql}
  308. ) AS T1
  309. JOIN
  310. (
  311. SELECT T1.sys_org_id, T1.exam_student_id, SUM(T1.score) AS total_score
  312. FROM exam_score AS T1
  313. {whereSql}
  314. GROUP BY T1.sys_org_id, T1.exam_student_id
  315. ) AS T2 ON T1.sys_org_id = T2.sys_org_id AND T1.exam_student_id = T2.exam_student_id
  316. WHERE T1.score >= {courseLine.LineScore} AND T2.total_score >= {totalLineScore}
  317. GROUP BY T1.sys_org_id
  318. ) AS T1
  319. JOIN
  320. (
  321. SELECT T1.sys_org_id, COUNT(1) as total_count
  322. FROM exam_score AS T1
  323. {courseWhereSql}
  324. GROUP BY T1.sys_org_id
  325. ) AS T2 ON T1.sys_org_id = T2.sys_org_id;
  326. ");
  327. // 班级 - 单上线
  328. await rep.SqlNonQueryAsync(@$"
  329. INSERT INTO esa_line_course(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, course_id, grade_id, sys_org_id, school_class_id, class_number, line_count, total_count, line_rate, is_double_line)
  330. SELECT {(short)EsaLevel.DISTRICT}, {(short)EsaDataScopeType.CLASS}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {courseLine.CourseId}, {esaBaseLine.GradeId}, T1.sys_org_id, T1.school_class_id, T1.class_number, T1.line_count, T2.total_count, T1.line_count / T2.total_count, 0
  331. FROM
  332. (
  333. SELECT T1.sys_org_id, T1.school_class_id, T1.class_number, COUNT(1) AS line_count
  334. FROM exam_score AS T1
  335. {courseWhereSql} AND T1.score >= {courseLine.LineScore}
  336. GROUP BY T1.sys_org_id, T1.school_class_id, T1.class_number
  337. ) AS T1
  338. JOIN
  339. (
  340. SELECT T1.sys_org_id, T1.school_class_id, T1.class_number, COUNT(1) as total_count
  341. FROM exam_score AS T1
  342. {courseWhereSql}
  343. GROUP BY T1.sys_org_id, T1.school_class_id, T1.class_number
  344. ) AS T2 ON T1.sys_org_id = T2.sys_org_id AND T1.school_class_id = T2.school_class_id AND T1.class_number = T2.class_number;
  345. ");
  346. // 班级 - 双上线
  347. await rep.SqlNonQueryAsync(@$"
  348. INSERT INTO esa_line_course(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, course_id, grade_id, sys_org_id, school_class_id, class_number, line_count, total_count, line_rate, is_double_line)
  349. SELECT {(short)EsaLevel.DISTRICT}, {(short)EsaDataScopeType.CLASS}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {courseLine.CourseId}, {esaBaseLine.GradeId}, T1.sys_org_id, T1.school_class_id, T1.class_number, T1.line_count, T2.total_count, T1.line_count / T2.total_count, 1
  350. FROM
  351. (
  352. SELECT T1.sys_org_id, T1.school_class_id, T1.class_number, COUNT(1) AS line_count
  353. FROM
  354. (
  355. SELECT T1.sys_org_id, T1.school_class_id, T1.class_number, T1.exam_student_id, T1.score
  356. FROM exam_score AS T1
  357. {courseWhereSql}
  358. ) AS T1
  359. JOIN
  360. (
  361. SELECT T1.sys_org_id, T1.school_class_id, T1.class_number, T1.exam_student_id, SUM(T1.score) AS total_score
  362. FROM exam_score AS T1
  363. {whereSql}
  364. GROUP BY T1.sys_org_id, T1.school_class_id, T1.class_number, T1.exam_student_id
  365. ) AS T2 ON T1.sys_org_id = T2.sys_org_id AND T1.school_class_id = T2.school_class_id AND T1.class_number = T2.class_number AND T1.exam_student_id = T2.exam_student_id
  366. WHERE T1.score >= {courseLine.LineScore} AND T2.total_score >= {totalLineScore}
  367. GROUP BY T1.sys_org_id, T1.school_class_id, T1.class_number
  368. ) AS T1
  369. JOIN
  370. (
  371. SELECT T1.sys_org_id, T1.school_class_id, T1.class_number, COUNT(1) as total_count
  372. FROM exam_score AS T1
  373. {courseWhereSql}
  374. GROUP BY T1.sys_org_id, T1.school_class_id, T1.class_number
  375. ) AS T2 ON T1.sys_org_id = T2.sys_org_id AND T1.school_class_id = T2.school_class_id AND T1.class_number = T2.class_number;
  376. ");
  377. }
  378. #endregion
  379. #endregion
  380. // TODO: 只生成区级层面
  381. if (false)
  382. {
  383. #region 学校分析
  384. var orgTotalLines = await rep.Change<EsaLineTotal>()
  385. .DetachedEntities
  386. .Where(t => t.EsaLevel == EsaLevel.DISTRICT &&
  387. t.EsaLineLevel == esaBaseLine.EsaLineLevel &&
  388. t.EsaDataScopeType == EsaDataScopeType.ORG &&
  389. t.GradeId == esaBaseLine.GradeId
  390. ).OrderBy(t => t.SysOrgId).ToListAsync();
  391. foreach (var orgTotalLine in orgTotalLines)
  392. {
  393. // 构造取数条件
  394. var orgWhereBaseSql = $"WHERE T1.exam_plan_id = {plan.ExamPlanId} AND T1.grade_id = {esaBaseLine.GradeId} AND T1.score > 0 AND T1.sys_org_id = {orgTotalLine.SysOrgId}";
  395. var orgWhereSql = $"{orgWhereBaseSql} AND T1.course_id IN ({courseIds})";
  396. #region 总分划线
  397. // 总学生数量
  398. var orgTotalCount = await rep.SqlScalarAsync<int>($@"
  399. SELECT COUNT(1) AS total_count
  400. FROM
  401. (
  402. SELECT T1.exam_student_id
  403. FROM exam_score AS T1
  404. {orgWhereSql}
  405. GROUP BY T1.exam_student_id
  406. ) AS T1;
  407. ");
  408. // 总分上线分
  409. var orgTotalLineScore = await rep.SqlScalarAsync<decimal>($@"
  410. SELECT MIN(total_score) AS line_score
  411. FROM
  412. (
  413. SELECT ROW_NUMBER() OVER(ORDER BY total_score DESC) AS rn, total_score
  414. FROM
  415. (
  416. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  417. FROM exam_score AS T1
  418. {orgWhereSql}
  419. GROUP BY T1.exam_student_id
  420. ) AS T1
  421. ) AS T1
  422. WHERE T1.rn <= ROUND({orgTotalCount} * {orgTotalLine.LineRate}, 0);
  423. ");
  424. // 总分上线均分
  425. var orgTotalLineAvgScore = Math.Round(await rep.SqlScalarAsync<decimal>(@$"
  426. SELECT AVG(T1.total_score) AS line_avg_score
  427. FROM
  428. (
  429. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  430. FROM exam_score AS T1
  431. {orgWhereSql}
  432. GROUP BY T1.exam_student_id
  433. ) AS T1
  434. WHERE T1.total_score >= {orgTotalLineScore};
  435. "), 2);
  436. // 更新有效系数
  437. var orgFactor = Math.Round(orgTotalLineScore / orgTotalLineAvgScore, 8);
  438. await rep.SqlNonQueryAsync($"UPDATE esa_line_total SET factor = {orgFactor} WHERE id = {orgTotalLine.Id}");
  439. // 实际上线人数
  440. var orgFactLineCount = await rep.SqlScalarAsync($@"
  441. SELECT COUNT(1) AS line_count
  442. FROM
  443. (
  444. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  445. FROM exam_score AS T1
  446. {orgWhereSql}
  447. GROUP BY T1.exam_student_id
  448. ) AS T1
  449. WHERE T1.total_score >= {orgTotalLineScore};
  450. ");
  451. // 总均分
  452. var orgTotalAvgScore = Math.Round(await rep.SqlScalarAsync<decimal>(@$"
  453. SELECT AVG(total_score) AS avg_score
  454. FROM
  455. (
  456. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  457. FROM exam_score AS T1
  458. {orgWhereSql}
  459. GROUP BY T1.exam_student_id
  460. ) AS T1;
  461. "), 2);
  462. // 学科有效分
  463. var orgTotalRelativeDiff = Math.Round((orgTotalLineScore - orgTotalAvgScore) / orgTotalLineScore, 8);
  464. await rep.SqlNonQueryAsync(@$"
  465. -- 总分
  466. INSERT INTO esa_line_course_score(esa_level, esa_line_level, esa_plan_id, esa_base_line_id, grade_id, sys_org_id, course_id, avg_score, line_avg_score, line_score, relative_diff)
  467. VALUES({(short)EsaLevel.ORG}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {esaBaseLine.GradeId}, {orgTotalLine.SysOrgId}, {(short)MultCourse.TOTAL}, {orgTotalAvgScore}, {orgTotalLineAvgScore}, {orgTotalLineScore}, {orgTotalRelativeDiff});
  468. -- 单科
  469. INSERT INTO esa_line_course_score(esa_level, esa_line_level, esa_plan_id, esa_base_line_id, grade_id, sys_org_id, course_id, avg_score, line_avg_score, line_score, relative_diff)
  470. SELECT {(short)EsaLevel.ORG}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {esaBaseLine.GradeId}, {orgTotalLine.SysOrgId}, T1.course_id, T2.avg_course_score, T1.avg_line_course_score, T1.course_line_score, ROUND((T1.course_line_score - T2.avg_course_score) / T1.course_line_score, 8) AS relative_diff
  471. FROM
  472. (
  473. SELECT T1.course_id, ROUND(AVG(T1.score), 2) AS avg_line_course_score, ROUND(ROUND(AVG(T1.score), 2) * {orgFactor}, 2) AS course_line_score
  474. FROM
  475. (
  476. SELECT T1.exam_student_id, T1.course_id, T1.score
  477. FROM exam_score AS T1
  478. {orgWhereSql}
  479. ) AS T1
  480. JOIN
  481. (
  482. SELECT T1.exam_student_id
  483. FROM
  484. (
  485. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  486. FROM exam_score AS T1
  487. {orgWhereSql}
  488. GROUP BY T1.exam_student_id
  489. ) AS T1
  490. WHERE T1.total_score >= {orgTotalLineScore}
  491. ) AS T2 ON T1.exam_student_id = T2.exam_student_id
  492. GROUP BY T1.course_id
  493. ) AS T1
  494. JOIN
  495. (
  496. SELECT T1.course_id, ROUND(AVG(T1.score), 2) AS avg_course_score
  497. FROM exam_score AS T1
  498. {orgWhereSql}
  499. GROUP BY T1.course_id
  500. ) AS T2 ON T1.course_id = T2.course_id;
  501. ");
  502. //// TODO: 临时终止
  503. //continue;
  504. // 学校
  505. await rep.SqlNonQueryAsync(@$"
  506. INSERT INTO esa_line_total(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, grade_id, sys_org_id, line_count, total_count, line_rate, factor)
  507. SELECT {(short)EsaLevel.ORG}, {(short)EsaDataScopeType.ORG}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {esaBaseLine.GradeId}, {orgTotalLine.SysOrgId}, COUNT(1) AS line_count, T2.total_count, COUNT(1) / T2.total_count, 0
  508. FROM
  509. (
  510. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  511. FROM exam_score AS T1
  512. {orgWhereSql}
  513. GROUP BY T1.exam_student_id
  514. ) AS T1
  515. JOIN
  516. (
  517. SELECT COUNT(1) as total_count
  518. FROM
  519. (
  520. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  521. FROM exam_score AS T1
  522. {orgWhereSql}
  523. GROUP BY T1.exam_student_id
  524. ) AS T1
  525. ) AS T2 ON 1 = 1
  526. WHERE T1.total_score >= {orgTotalLineScore};
  527. ");
  528. // 班级
  529. await rep.SqlNonQueryAsync(@$"
  530. INSERT INTO esa_line_total(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, grade_id, sys_org_id, school_class_id, class_number, line_count, total_count, line_rate, factor)
  531. SELECT {(short)EsaLevel.ORG}, {(short)EsaDataScopeType.CLASS}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {esaBaseLine.GradeId}, {orgTotalLine.SysOrgId}, T1.school_class_id, T1.class_number, COUNT(1) AS line_count, T2.total_count, COUNT(1) / T2.total_count, 0
  532. FROM
  533. (
  534. SELECT T1.school_class_id, T1.class_number, T1.exam_student_id, SUM(T1.score) AS total_score
  535. FROM exam_score AS T1
  536. {orgWhereSql}
  537. GROUP BY T1.school_class_id, T1.class_number, T1.exam_student_id
  538. ) AS T1
  539. JOIN
  540. (
  541. SELECT T1.school_class_id, T1.class_number, COUNT(1) as total_count
  542. FROM
  543. (
  544. SELECT T1.school_class_id, T1.class_number, T1.exam_student_id, SUM(T1.score) AS total_score
  545. FROM exam_score AS T1
  546. {orgWhereSql}
  547. GROUP BY T1.school_class_id, T1.class_number, T1.exam_student_id
  548. ) AS T1
  549. GROUP BY T1.school_class_id, T1.class_number
  550. ) AS T2 ON T1.school_class_id = T2.school_class_id AND T1.class_number = T2.class_number
  551. WHERE T1.total_score >= {orgTotalLineScore}
  552. GROUP BY T1.school_class_id, T1.class_number;
  553. ");
  554. #endregion
  555. #region 学科划线
  556. var orgCourseLines = await rep.Change<EsaLineCourseScore>().DetachedEntities
  557. .Where(t => t.EsaPlanId == esaPlanId &&
  558. t.EsaBaseLineId == esaBaseLine.Id &&
  559. t.EsaLevel == EsaLevel.ORG &&
  560. t.EsaLineLevel == esaBaseLine.EsaLineLevel &&
  561. t.GradeId == esaBaseLine.GradeId &&
  562. t.SysOrgId == orgTotalLine.SysOrgId &&
  563. t.CourseId != (short)MultCourse.TOTAL
  564. ).ToListAsync();
  565. foreach (var orgCourseLine in orgCourseLines)
  566. {
  567. // 单科条件
  568. var orgCourseWhereSql = $"{orgWhereBaseSql} AND T1.course_id = {orgCourseLine.CourseId}";
  569. // 学校 - 单上线
  570. await rep.SqlNonQueryAsync(@$"
  571. INSERT INTO esa_line_course(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, course_id, grade_id, sys_org_id, line_count, total_count, line_rate, is_double_line)
  572. SELECT {(short)EsaLevel.ORG}, {(short)EsaDataScopeType.ORG}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {orgCourseLine.CourseId}, {esaBaseLine.GradeId}, {orgTotalLine.SysOrgId}, T1.line_count, T2.total_count, T1.line_count / T2.total_count, 0
  573. FROM
  574. (
  575. SELECT COUNT(1) AS line_count
  576. FROM exam_score AS T1
  577. {orgCourseWhereSql} AND T1.score >= {orgCourseLine.LineScore}
  578. ) AS T1
  579. JOIN
  580. (
  581. SELECT COUNT(1) as total_count
  582. FROM exam_score AS T1
  583. {orgCourseWhereSql}
  584. ) AS T2 ON 1 = 1;
  585. ");
  586. // 学校 - 双上线
  587. await rep.SqlNonQueryAsync(@$"
  588. INSERT INTO esa_line_course(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, course_id, grade_id, sys_org_id, line_count, total_count, line_rate, is_double_line)
  589. SELECT {(short)EsaLevel.ORG}, {(short)EsaDataScopeType.ORG}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {orgCourseLine.CourseId}, {esaBaseLine.GradeId}, {orgTotalLine.SysOrgId}, T1.line_count, T2.total_count, T1.line_count / T2.total_count, 1
  590. FROM
  591. (
  592. SELECT COUNT(1) AS line_count
  593. FROM
  594. (
  595. SELECT T1.exam_student_id, T1.score
  596. FROM exam_score AS T1
  597. {orgCourseWhereSql}
  598. ) AS T1
  599. JOIN
  600. (
  601. SELECT T1.exam_student_id, SUM(T1.score) AS total_score
  602. FROM exam_score AS T1
  603. {orgWhereSql}
  604. GROUP BY T1.exam_student_id
  605. ) AS T2 ON T1.exam_student_id = T2.exam_student_id
  606. WHERE T1.score >= {orgCourseLine.LineScore} AND T2.total_score >= {orgTotalLineScore}
  607. ) AS T1
  608. JOIN
  609. (
  610. SELECT COUNT(1) as total_count
  611. FROM exam_score AS T1
  612. {orgCourseWhereSql}
  613. ) AS T2 ON 1 = 1;
  614. ");
  615. // 班级 - 单上线
  616. await rep.SqlNonQueryAsync(@$"
  617. INSERT INTO esa_line_course(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, course_id, grade_id, sys_org_id, school_class_id, class_number, line_count, total_count, line_rate, is_double_line)
  618. SELECT {(short)EsaLevel.ORG}, {(short)EsaDataScopeType.CLASS}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {orgCourseLine.CourseId}, {esaBaseLine.GradeId}, {orgTotalLine.SysOrgId}, T1.school_class_id, T1.class_number, T1.line_count, T2.total_count, T1.line_count / T2.total_count, 0
  619. FROM
  620. (
  621. SELECT T1.school_class_id, T1.class_number, COUNT(1) AS line_count
  622. FROM exam_score AS T1
  623. {orgCourseWhereSql} AND T1.score >= {orgCourseLine.LineScore}
  624. GROUP BY T1.school_class_id, T1.class_number
  625. ) AS T1
  626. JOIN
  627. (
  628. SELECT T1.school_class_id, T1.class_number, COUNT(1) as total_count
  629. FROM exam_score AS T1
  630. {orgCourseWhereSql}
  631. GROUP BY T1.school_class_id, T1.class_number
  632. ) AS T2 ON T1.school_class_id = T2.school_class_id AND T1.class_number = T2.class_number;
  633. ");
  634. // 班级 - 双上线
  635. await rep.SqlNonQueryAsync(@$"
  636. INSERT INTO esa_line_course(esa_level, esa_data_scope_type, esa_line_level, esa_plan_id, esa_base_line_id, course_id, grade_id, sys_org_id, school_class_id, class_number, line_count, total_count, line_rate, is_double_line)
  637. SELECT {(short)EsaLevel.ORG}, {(short)EsaDataScopeType.CLASS}, {(short)esaBaseLine.EsaLineLevel}, {esaPlanId}, {esaBaseLine.Id}, {orgCourseLine.CourseId}, {esaBaseLine.GradeId}, {orgTotalLine.SysOrgId}, T1.school_class_id, T1.class_number, T1.line_count, T2.total_count, T1.line_count / T2.total_count, 1
  638. FROM
  639. (
  640. SELECT T1.school_class_id, T1.class_number, COUNT(1) AS line_count
  641. FROM
  642. (
  643. SELECT T1.school_class_id, T1.class_number, T1.exam_student_id, T1.score
  644. FROM exam_score AS T1
  645. {orgCourseWhereSql}
  646. ) AS T1
  647. JOIN
  648. (
  649. SELECT T1.school_class_id, T1.class_number, T1.exam_student_id, SUM(T1.score) AS total_score
  650. FROM exam_score AS T1
  651. {orgWhereSql}
  652. GROUP BY T1.school_class_id, T1.class_number, T1.exam_student_id
  653. ) AS T2 ON T1.school_class_id = T2.school_class_id AND T1.class_number = T2.class_number AND T1.exam_student_id = T2.exam_student_id
  654. WHERE T1.score >= {orgCourseLine.LineScore} AND T2.total_score >= {orgTotalLineScore}
  655. GROUP BY T1.school_class_id, T1.class_number
  656. ) AS T1
  657. JOIN
  658. (
  659. SELECT T1.school_class_id, T1.class_number, COUNT(1) as total_count
  660. FROM exam_score AS T1
  661. {orgCourseWhereSql}
  662. GROUP BY T1.school_class_id, T1.class_number
  663. ) AS T2 ON T1.school_class_id = T2.school_class_id AND T1.class_number = T2.class_number;
  664. ");
  665. }
  666. #endregion
  667. }
  668. #endregion
  669. }
  670. // 更新状态
  671. await rep.SqlNonQueryAsync($"UPDATE esa_base_line SET status = {(short)ProcessingStatus.SUCCESSFUL} WHERE id = {esaBaseLine.Id}");
  672. }
  673. catch (Exception)
  674. {
  675. // 更新状态
  676. await rep.SqlNonQueryAsync($"UPDATE esa_base_line SET status = {(short)ProcessingStatus.FAILED} WHERE id = {esaBaseLine.Id}");
  677. throw;
  678. }
  679. }
  680. // 更新状态
  681. await rep.SqlNonQueryAsync($"UPDATE esa_plan SET status = {(short)ProcessingStatus.SUCCESSFUL} WHERE id = {esaPlanId}");
  682. }
  683. catch (Exception)
  684. {
  685. // 更新状态
  686. await rep.SqlNonQueryAsync($"UPDATE esa_plan SET status = {(short)ProcessingStatus.FAILED} WHERE id = {esaPlanId}");
  687. throw;
  688. }
  689. }
  690. }