AS

<particleEmitterConfig>
  <texture name="texture.png"/>
  <sourcePosition x="300.00" y="300.00"/>
  <sourcePositionVariance x="0" y="0.00"/>
  <speed value="30"/>
  <speedVariance value="108.33"/>
  <particleLifeSpan value="2.0000"/>
  <particleLifespanVariance value="1.9000"/>
  <angle value="270.00"/>
  <angleVariance value="144.88"/>
  <gravity x="0.00" y="0.00"/>
  <radialAcceleration value="0.00"/>
  <tangentialAcceleration value="-5.88"/>
  <radialAccelVariance value="0.00"/>
  <tangentialAccelVariance value="74.63"/>
  <startColor red="0.14" green="0.48" blue="0.23" alpha="0.33"/>
  <startColorVariance red="0.18" green="0.28" blue="0.33" alpha="0.00"/>
  <finishColor red="0.26" green="0.31" blue="0.75" alpha="1"/>
  <finishColorVariance red="0.5700000000000001" green="0.12" blue="0.88" alpha="0.00"/>
  <maxParticles value="500.5"/>
  <startParticleSize value="10.120000000000001"/>
  <startParticleSizeVariance value="70"/>
  <finishParticleSize value="54.63"/>
  <FinishParticleSizeVariance value="5.00"/>
  <duration value="-1.00"/>
  <emitterType value="0"/>
  <maxRadius value="198.72"/>
  <maxRadiusVariance value="61.22"/>
  <minRadius value="61.730000000000004"/>
  <rotatePerSecond value="-190.11"/>
  <rotatePerSecondVariance value="31.76"/>
  <blendFuncSource value="770"/>
  <blendFuncDestination value="1"/>
  <rotationStart value="0.00"/>
  <rotationStartVariance value="147.54"/>
  <rotationEnd value="0.00"/>
  <rotationEndVariance value="0.00"/>
</particleEmitterConfig>

内容概要:本文详细介绍了一个基于Java和Vue的联邦学习隐私保护推荐系统的设计与实现。系统采用联邦学习架构,使用户数据在本地完成模型训练,仅上传加密后的模型参数或梯度,通过中心服务器进行联邦平均聚合,从而实现数据隐私保护与协同建模的双重目标。项目涵盖完整的系统架构设计,包括本地模型训练、中心参数聚合、安全通信、前后端解耦、推荐算法插件化等模块,并结合差分隐私与同态加密等技术强化安全性。同时,系统通过Vue前端实现用户行为采集与个性化推荐展示,Java后端支撑高并发服务与日志处理,形成“本地训练&mdash;参数上传&mdash;全局聚合&mdash;模型下发&mdash;个性化微调”的完整闭环。文中还提供了关键模块的代码示例,如特征提取、模型聚合、加密上传等,增强了项目的可实施性与工程参考价值。 适合人群:具备一定Java和Vue开发基础,熟悉Spring Boot、RESTful API、分布式系统或机器学习相关技术,从事推荐系统、隐私计算或全栈开发方向的研发人员。 使用场景及目标:①学习联邦学习在推荐系统中的工程落地方法;②掌握隐私保护机制(如加密传输、差分隐私)与模型聚合技术的集成;③构建高安全、可扩展的分布式推荐系统原型;④实现前后端协同的个性化推荐闭环系统。 阅读建议:建议结合代码示例深入理解联邦学习流程,重点关注本地训练与全局聚合的协同逻辑,同时可基于项目架构进行算法替换与功能扩展,适用于科研验证与工业级系统原型开发。
源码来自:https://pan.quark.cn/s/a4b39357ea24 遗传算法 - 简书 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 遗传算法(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是进化算法的一种。 进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择、杂交等。 搜索算法的共同特征为: 首先组成一组候选解 依据某些适应性条件测算这些候选解的适应度 根据适应度保留某些候选解,放弃其他候选解 对保留的候选解进行某些操作,生成新的候选解 遗传算法流程 遗传算法的一般步骤 my_fitness函数 评估每条染色体所对应个体的适应度 升序排列适应度评估值,选出 前 parent_number 个 个体作为 待选 parent 种群(适应度函数的值越小越好) 从 待选 parent 种群 中随机选择 2 个个体作为父方和母方。 抽取父母双方的染色体,进行交叉,产生 2 个子代。 (交叉概率) 对子代(parent + 生成的 child)的染色体进行变异。 (变异概率) 重复3,4,5步骤,直到新种群(parentnumber + childnumber)的产生。 循环以上步骤直至找到满意的解。 名词解释 交叉概率:两个个体进行交配的概率。 例如,交配概率为0.8,则80%的“夫妻”会生育后代。 变异概率:所有的基因中发生变异的占总体的比例。 GA函数 适应度函数 适应度函数由解决的问题决定。 举一个平方和的例子。 简单的平方和问题 求函数的最小值,其中每个变量的取值区间都是 [-1, ...
-- 公用日期表CTE(2025年各月份) WITH dom AS ( SELECT CONVERT(VARCHAR(6), DATEADD(MONTH, number, '2022-01-01'), 112) AS DateOfMonth FROM master..spt_values WHERE type = 'P' AND CONVERT(VARCHAR(6), DATEADD(MONTH, number, '2022-01-01'), 112) LIKE '2025%' ) -- 缸体产线数据 SELECT '缸体' AS 产线, rn, 年月, 不良类型, 不良数, 产量, 不良率 FROM ( -- 缸体产线原始SQL(保持内容不变) SELECT '1' rn, '22年' AS 年月, '高压铸造' 不良类型, 83 不良数, 23564 产量, 0.10 不良率 UNION ALL SELECT '1', '23年', '高压铸造', 113, 31025, 0.16 UNION ALL SELECT '1', '24年', '高压铸造', 113, 31025, 0.141 UNION ALL SELECT '2', '01', '高压铸造', 10, 0, 0.015 UNION ALL SELECT '2', '04', '高压铸造', 25, 0, 0.02 UNION ALL SELECT '3', '平均', '高压铸造', 1, 31025, 0.0153 UNION ALL SELECT '2', RIGHT(dom.DateOfMonth, 2), td.不良类型, td.不良数, td.产量, CONVERT(DECIMAL(12,3), td.不良率*100) FROM dom LEFT JOIN ( SELECT '2' rn, '高压铸造' AS 不良类型, 年+月 AS 年月, CONVERT(DECIMAL(12,0), 合格数) AS 产量, CONVERT(DECIMAL(12,0), 不良数) AS 不良数, CASE WHEN 合格数 = 0 THEN 0 ELSE CONVERT(DECIMAL(12,7), 不良数/合格数) END AS 不良率 FROM ( SELECT duty, 年, 月, SUM(合格数) 合格数, SUM(不良数) 不良数 FROM [192.168.10.116].GLKANBAN.dbo.V_铸造日报_C WHERE duty = '高压铸造' AND 年 = '2025' GROUP BY duty, 年, 月 ) A UNION ALL SELECT '2', '返修品', t1.年月, t1.合格数 + t1.不良数 + 数量, 数量, CONVERT(DECIMAL(12,7), 数量/(合格数)) FROM ( SELECT 年+月 AS 年月, SUM(合格数) 合格数, SUM(不良数) AS 不良数 FROM [192.168.10.116].GLKANBAN.dbo.V_铸造日报_C WHERE duty = '高压铸造' AND 年 = '2025' GROUP BY 年, 月 ) t1 LEFT JOIN ( SELECT LEFT(REPLACE(日期, '/', ''),6) AS 年月, ISNULL(SUM(数量), 1) AS 数量 FROM [192.168.10.116].GLKANBAN.dbo.T_铸造_缸体缸盖返修记录表 WHERE 类型 = '缸体毛坯' AND LEFT(日期, 4) = '2025' GROUP BY LEFT(REPLACE(日期, '/', ''),6) ) t2 ON t1.年月 = t2.年月 WHERE t2.数量 IS NOT NULL ) td ON dom.DateOfMonth = td.年月 UNION ALL SELECT '2', '平均', '高压铸造', CONVERT(DECIMAL(12,0), 不良数)/5, CONVERT(DECIMAL(12,0), 合格数), CASE WHEN 合格数 = 0 THEN 0 ELSE CONVERT(DECIMAL(12,7), 不良数/合格数)*100 END FROM dom LEFT JOIN ( SELECT '2' rn, '缸体报废' AS 不良类型, REPLACE(年月, '/', '') AS 年月, SUM(成品) AS 产量, SUM(不良数) AS 不良数, CASE WHEN SUM(成品) = 0 THEN 0 ELSE SUM(不良数)/SUM(成品) END AS 不良率 FROM ( SELECT LEFT(生产日期, 7) AS 年月, SUM(CONVERT(DECIMAL(4,0), 完成品)) AS 成品, SUM(CONVERT(DECIMAL(3,0), 不良数)) AS 不良数 FROM [192.168.10.116].GLKANBAN.[dbo].[V_铸造日报_M] WHERE 生产日期 > '2023/12/31' AND 产线 = '缸体线' GROUP BY LEFT(生产日期, 7) ) A GROUP BY 年月 UNION ALL SELECT '2', '返修品', t1.年月, t1.台数, t2.数量, CONVERT(DECIMAL(12,7), t2.数量/(t1.台数 + t2.数量)) FROM ( SELECT REPLACE(年月, '/', '') AS 年月, SUM(成品) AS 台数 FROM ( SELECT LEFT(生产日期, 7) AS 年月, SUM(CONVERT(DECIMAL(4,0), 完成品)) AS 成品 FROM [192.168.10.116].GLKANBAN.[dbo].[V_铸造日报_M] WHERE LEFT(生产日期, 4) = '2025' AND 产线 = '缸体线' GROUP BY LEFT(生产日期, 7) ) B GROUP BY 年月 ) t1 LEFT JOIN ( SELECT LEFT(REPLACE(日期, '/', ''),6) AS 年月, ISNULL(COUNT(*), 0) AS 数量 FROM [192.168.10.116].[GLKANBAN].[dbo].[T_铸造_缸体缸盖返修记录表] WHERE 类型 = '缸体' AND LEFT(日期, 4) = '2025' GROUP BY LEFT(REPLACE(日期, '/', ''),6) ) t2 ON t1.年月 = t2.年月 WHERE t2.数量 IS NOT NULL ) td ON dom.DateOfMonth = td.年月 UNION ALL ) AS 缸体数据 UNION ALL -- 关键合并点 -- 缸盖产线数据 SELECT '缸盖' AS 产线, rn, 年月, 不良类型, 不良数, 产量, 不良率 FROM ( SELECT '1' rn, '22年' AS 年月, '低压铸造' AS 不良类型, 400 AS 不良数, 43782 AS 产量, 1.11 AS 不良率 UNION ALL SELECT '1' rn, '22年' AS 年月, '返修品' AS 不良类型, 1 AS 不良数, 1 AS 产量, 0 AS 不良率 UNION ALL SELECT '1' rn, '23年' AS 年月, '低压铸造' AS 不良类型, 209 AS 不良数, 68233 AS 产量, 0.63 AS 不良率 UNION ALL SELECT '1' rn, '23年' AS 年月, '返修品' AS 不良类型, 1 AS 不良数, 1 AS 产量, 0 AS 不良率 UNION ALL SELECT '1' rn, '24年' AS 年月, '低压铸造' AS 不良类型, 209 AS 不良数, 68233 AS 产量, 0.613 AS 不良率 UNION ALL SELECT '1' rn, '24年' AS 年月, '返修品' AS 不良类型, 121 AS 不良数, 609591 AS 产量, 0.23 AS 不良率 UNION ALL SELECT '2' rn, '01' AS 年月, '低压铸造' AS 不良类型, 1 AS 不良数, 1 AS 产量, 0.02 AS 不良率 UNION ALL SELECT '2' rn, '03' AS 年月, '低压铸造' AS 不良类型, 1 AS 不良数, 1 AS 产量, 0.03 AS 不良率 UNION ALL SELECT '2' rn, '04' AS 年月, '低压铸造' AS 不良类型, 1 AS 不良数, 1 AS 产量, -0.02 AS 不良率 UNION ALL SELECT '2' rn, '07' AS 年月, '低压铸造' AS 不良类型, 1 AS 不良数, 1 AS 产量, -0.063 AS 不良率 UNION ALL SELECT '2' rn, '09' AS 年月, '返修品' AS 不良类型, 1 AS 不良数, 1 AS 产量, 0 AS 不良率 UNION ALL SELECT '2' rn, '10' AS 年月, '返修品' AS 不良类型, 1 AS 不良数, 1 AS 产量, 0 AS 不良率 UNION ALL SELECT '3' rn, '平均' AS 年月, '低压铸造' AS 不良类型, 0 AS 不良数, 68233 AS 产量, 0.026 AS 不良率 UNION ALL SELECT '3' rn, '平均' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 1 AS 产量, 0.03 AS 不良率 UNION ALL SELECT '2' rn, RIGHT(dom.DateOfMonth, 2) AS 年月, 不良类型, 不良数, 产量, CONVERT(DECIMAL(12, 3), 不良率 * 100) AS 不良率 FROM dom LEFT JOIN ( SELECT '2' rn, 产品 AS 不良类型, CONCAT(年, 月) AS 年月, CONVERT(DECIMAL(12, 0), 合格数) AS 产量, CONVERT(DECIMAL(12, 0), 不良数) AS 不良数, CASE WHEN 合格数 = 0 THEN 0 ELSE CONVERT(DECIMAL(12, 7), 不良数 / 合格数) END AS 不良率 FROM ( SELECT duty AS 产品, 年, 月, SUM(合格数) AS 合格数, SUM(不良数) AS 不良数 FROM [192.168.10.116].GLKANBAN.dbo.V_铸造日报_C WHERE duty = '低压铸造' GROUP BY duty, 年, 月 ) A WHERE 年 = '2025' UNION ALL SELECT '2' rn, 类型 AS 不良类型, t1.年月, 合格数, 数量, CONVERT(DECIMAL(12, 7), 数量 / 合格数) AS 不良率 FROM ( SELECT CONCAT(年, 月) AS 年月, SUM(合格数) AS 合格数, SUM(不良数) AS 不良数 FROM [192.168.10.116].GLKANBAN.dbo.V_铸造日报_C WHERE duty = '低压铸造' GROUP BY duty, 年, 月 ) t1 LEFT JOIN ( SELECT LEFT(REPLACE(日期, '/', ''), 6) AS 年月, ISNULL(SUM(数量), 1) AS 数量, '返修品' AS 类型 FROM [192.168.10.116].GLKANBAN.dbo.T_铸造_缸体缸盖返修记录表 WHERE 类型 = '缸盖毛坯' AND LEFT(日期, 4) = '2025' GROUP BY LEFT(REPLACE(日期, '/', ''), 6) ) t2 ON t1.年月 = t2.年月 WHERE 类型 IS NOT NULL ) td ON dom.DateOfMonth = td.年月 UNION ALL SELECT '2' rn, 月 AS 年月, 产品 AS 不良类型, CONVERT(DECIMAL(12, 0), 不良数) / 7.3 AS 平均不良数, CONVERT(DECIMAL(12, 0), 合格数) AS 合格数, CASE WHEN 合格数 = 0 THEN 0 ELSE CONVERT(DECIMAL(12, 7), 不良数 / 合格数) * 100 END AS 平均不良率 FROM ( SELECT duty AS 产品, 年, '平均' AS 月, SUM(合格数) AS 合格数, SUM(不良数) AS 不良数 FROM [192.168.10.116].GLKANBAN.dbo.V_铸造日报_C WHERE duty = '低压铸造' GROUP BY duty, 年 ) A WHERE 年 = '2025' ) AS low_pressure UNION ALL SELECT '缸盖' AS 产线, rn, 年月, 不良类型, 不良数, 产量, 不良率 FROM ( SELECT '1' rn, '22年' AS 年月, '低压铸造' AS 不良类型, 400 AS 不良数, 43782 AS 产量, 1.11 AS 不良率 UNION ALL -- 缸盖产线数据 (原缸盖线) SELECT '缸盖' AS 产线, rn, 年月, 不良类型, 不良数, 产量, 不良率 FROM ( SELECT '1' rn, '22年' AS 年月, '缸盖报废' AS 不良类型, 357 AS 不良数, 43782 AS 产量, 0.65 AS 不良率 UNION ALL SELECT '1' rn, '22年' AS 年月, '返修品' AS 不良类型, 1 AS 不良数, 1 AS 产量, 0 AS 不良率 UNION ALL SELECT '1' rn, '23年' AS 年月, '缸盖报废' AS 不良类型, 160 AS 不良数, 68233 AS 产量, 0.29 AS 不良率 UNION ALL SELECT '1' rn, '23年' AS 年月, '返修品' AS 不良类型, 1 AS 不良数, 1 AS 产量, 0 AS 不良率 UNION ALL SELECT '1' rn, '24年' AS 年月, '缸盖报废' AS 不良类型, 160 AS 不良数, 68233 AS 产量, 0.308 AS 不良率 UNION ALL SELECT '1' rn, '24年' AS 年月, '返修品' AS 不良类型, 94 AS 不良数, 564760 AS 产量, 0.214 AS 不良率 UNION ALL SELECT '2' rn, '01' AS 年月, '缸盖报废' AS 不良类型, 1 AS 不良数, 0 AS 产量, 0.015 AS 不良率 UNION ALL SELECT '2' rn, '04' AS 年月, '缸盖报废' AS 不良类型, 45 AS 不良数, 0 AS 产量, 0.03 AS 不良率 UNION ALL SELECT '2' rn, '07' AS 年月, '缸盖报废' AS 不良类型, 45 AS 不良数, 0 AS 产量, 0.05 AS 不良率 UNION ALL SELECT '2' rn, '08' AS 年月, '缸盖报废' AS 不良类型, 45 AS 不良数, 0 AS 产量, 1.0 AS 不良率 UNION ALL SELECT '2' rn, '02' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 0 AS 产量, 0 AS 不良率 UNION ALL SELECT '2' rn, '04' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 0 AS 产量, 0 AS 不良率 UNION ALL SELECT '2' rn, '08' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 0 AS 产量, 0 AS 不良率 UNION ALL SELECT '2' rn, '09' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 0 AS 产量, 0 AS 不良率 UNION ALL SELECT '2' rn, '10' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 0 AS 产量, 0 AS 不良率 UNION ALL SELECT '3' rn, '平均' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 1 AS 产量, 0.001 AS 不良率 UNION ALL SELECT '2' rn, RIGHT(dom.DateOfMonth, 2) AS 年月, 不良类型, 不良数, 产量, CONVERT(DECIMAL(12, 3), 不良率 * 100) AS 不良率 FROM dom LEFT JOIN ( SELECT '2' AS rn, '缸盖报废' AS 不良类型, REPLACE(年月, '/', '') AS 年月, SUM(成品) AS 产量, SUM(不良数) AS 不良数, CASE WHEN SUM(成品) = 0 THEN 0 ELSE SUM(不良数) / SUM(成品) END AS 不良率 FROM ( SELECT CASE WHEN 机型 LIKE '%2.0%' THEN 'TNGA2.0L' WHEN 机型 LIKE '%1.5%' THEN 'TNGA1.5L' ELSE 'TNGA2.5L' END AS LINE, LEFT(生产日期, 7) AS 年月, SUM(CONVERT(DECIMAL(4, 0), 完成品)) AS 成品, SUM(CONVERT(DECIMAL(3, 0), 不良数)) AS 不良数 FROM [192.168.10.116].GLKANBAN.[dbo].[V_铸造日报_M] WHERE 生产日期 > '2023-12-31' AND 产线 = '缸盖线' GROUP BY LEFT(生产日期, 7), 机型 ) A GROUP BY 年月 -- 此处保持所有缸盖产线原始UNION ALL语句... SELECT '2' rn, RIGHT(dom.DateOfMonth, 2) AS 年月, 不良类型, 不良数, 产量, CONVERT(DECIMAL(12, 3), 不良率 * 100) AS 不良率 FROM dom LEFT JOIN (...) td ON dom.DateOfMonth = td.年月 ) AS low_pressure UNION ALL SELECT '缸盖' AS 产线, rn, 年月, 不良类型, 不良数, 产量, 不良率 FROM ( SELECT '1' rn, '22年' AS 年月, '缸盖报废' AS 不良类型, 357 AS 不良数, 43782 AS 产量, 0.65 AS 不良率 UNION ALL -- 缸盖产线数据 (原缸盖线) SELECT '缸盖' AS 产线, rn, 年月, 不良类型, 不良数, 产量, 不良率 FROM ( SELECT '1' rn, '22年' AS 年月, '缸盖报废' AS 不良类型, 357 AS 不良数, 43782 AS 产量, 0.65 AS 不良率 UNION ALL SELECT '1' rn, '22年' AS 年月, '返修品' AS 不良类型, 1 AS 不良数, 1 AS 产量, 0 AS 不良率 UNION ALL SELECT '1' rn, '23年' AS 年月, '缸盖报废' AS 不良类型, 160 AS 不良数, 68233 AS 产量, 0.29 AS 不良率 UNION ALL SELECT '1' rn, '23年' AS 年月, '返修品' AS 不良类型, 1 AS 不良数, 1 AS 产量, 0 AS 不良率 UNION ALL SELECT '1' rn, '24年' AS 年月, '缸盖报废' AS 不良类型, 160 AS 不良数, 68233 AS 产量, 0.308 AS 不良率 UNION ALL SELECT '1' rn, '24年' AS 年月, '返修品' AS 不良类型, 94 AS 不良数, 564760 AS 产量, 0.214 AS 不良率 UNION ALL SELECT '2' rn, '01' AS 年月, '缸盖报废' AS 不良类型, 1 AS 不良数, 0 AS 产量, 0.015 AS 不良率 UNION ALL SELECT '2' rn, '04' AS 年月, '缸盖报废' AS 不良类型, 45 AS 不良数, 0 AS 产量, 0.03 AS 不良率 UNION ALL SELECT '2' rn, '07' AS 年月, '缸盖报废' AS 不良类型, 45 AS 不良数, 0 AS 产量, 0.05 AS 不良率 UNION ALL SELECT '2' rn, '08' AS 年月, '缸盖报废' AS 不良类型, 45 AS 不良数, 0 AS 产量, 1.0 AS 不良率 UNION ALL SELECT '2' rn, '02' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 0 AS 产量, 0 AS 不良率 UNION ALL SELECT '2' rn, '04' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 0 AS 产量, 0 AS 不良率 UNION ALL SELECT '2' rn, '08' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 0 AS 产量, 0 AS 不良率 UNION ALL SELECT '2' rn, '09' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 0 AS 产量, 0 AS 不良率 UNION ALL SELECT '2' rn, '10' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 0 AS 产量, 0 AS 不良率 UNION ALL SELECT '3' rn, '平均' AS 年月, '返修品' AS 不良类型, 0 AS 不良数, 1 AS 产量, 0.001 AS 不良率 UNION ALL SELECT '2' rn, RIGHT(dom.DateOfMonth, 2) AS 年月, 不良类型, 不良数, 产量, CONVERT(DECIMAL(12, 3), 不良率 * 100) AS 不良率 FROM dom LEFT JOIN ( SELECT '2' AS rn, '缸盖报废' AS 不良类型, REPLACE(年月, '/', '') AS 年月, SUM(成品) AS 产量, SUM(不良数) AS 不良数, CASE WHEN SUM(成品) = 0 THEN 0 ELSE SUM(不良数) / SUM(成品) END AS 不良率 FROM ( SELECT CASE WHEN 机型 LIKE '%2.0%' THEN 'TNGA2.0L' WHEN 机型 LIKE '%1.5%' THEN 'TNGA1.5L' ELSE 'TNGA2.5L' END AS LINE, LEFT(生产日期, 7) AS 年月, SUM(CONVERT(DECIMAL(4, 0), 完成品)) AS 成品, SUM(CONVERT(DECIMAL(3, 0), 不良数)) AS 不良数 FROM [192.168.10.116].GLKANBAN.[dbo].[V_铸造日报_M] WHERE 生产日期 > '2023-12-31' AND 产线 = '缸盖线' GROUP BY LEFT(生产日期, 7), 机型 ) A GROUP BY 年月 SELECT '2' rn, RIGHT(dom.DateOfMonth, 2) AS 年月, 不良类型, 不良数, 产量, CONVERT(DECIMAL(12, 3), 不良率 * 100) AS 不良率 FROM dom LEFT JOIN (...) td ON dom.DateOfMonth = td.年月 ) AS head_line ) AS 缸盖数据 -- 最终排序 ORDER BY 产线, rn, 年月;
12-06
<think>我们有一个复杂的SQL查询,主要包含两部分: 1. 公用日期表CTE(dom):生成2025年的所有月份(格式为YYYYMM) 2. 一个包含多个UNION ALL的子查询,用于构建缸体线数据,并在最外层添加常量列'缸体'作为产线标识 需要对这个SQL进行优化、检查错误或分析功能。 观察提供的SQL代码,发现以下问题: 1. 日期CTE生成的是2025年的月份,但原始数据中有的年月是'22年','23年'等,格式不一致,可能导致连接失败。 2. 在缸体源数据的子查询中,有一部分是固定数据(UNION ALL多个固定行),另一部分是通过连接dom表(日期表)和某个表(用...表示,未给出具体表)来获取数据,还有一部分是计算平均值的部分(同样未给出具体表)。 3. 在连接dom表的部分,连接条件为`dom.DateOfMonth = td.年月`,但是dom.DateOfMonth是6位字符串(如'202501'),而固定数据中的年月是'01','04'等两位字符串,或者像'22年'这样的字符串,显然格式不匹配,这将导致连接不上。 4. 在计算平均值的部分,分母使用了“合格数”,但固定数据中并没有提供合格数字段,只有产量和不良数。注意:不良率=不良数/产量?但是这里的分母是合格数,而合格数=产量-不良数?但是SQL中直接使用了“合格数”字段,而固定数据中并没有这个字段。 另外,关于优化: - 使用CTE是合理的,但要注意CTE在SQL Server中会被多次执行(除非是递归CTE或者被多次引用,否则可能会被优化为只执行一次,但这里CTE只被引用一次,所以问题不大)。 - 但是,在子查询中,固定数据部分和动态部分混合,且格式不一致,这会导致数据混乱。 因此,我们需要重新设计这个查询,以解决上述问题。 根据原始需求(参考之前的对话),这个SQL的目的是将缸体线的数据(包含多个部分:固定行、按月份的数据、平均值)显示出来,并在最外层加上产线标识为“缸体”。 建议的修改: 1. 统一日期格式:在固定数据部分,将年月统一为两位的月份(如'01','02',...,'12')或者四位年份+两位月份(如'202501')。但根据后续连接,我们使用两位月份(因为dom表被截取为两位,但注意固定数据中还有'22年','23年'这样的值,这显然不是月份,而是年度数据,所以不能与月份数据混在一起)。 2. 重新组织数据结构:将固定数据(如年度数据、平均数据)与月份数据分开处理,避免格式冲突。 3. 对于连接dom表的部分,确保连接的两个字段类型和格式一致。 4. 在计算平均值的部分,需要明确数据来源。如果固定数据中没有合格数,那么应该用产量和不良数来计算。 由于原始SQL中部分表用...表示,我们无法得知具体结构,因此这里只能给出一个重构的框架。 重构思路: 将缸体线数据分为三个部分: A. 固定行(如年度汇总行、平均行等)&mdash;&mdash; 这些行不需要连接日期表 B. 月份数据行 &mdash;&mdash; 需要连接日期表,确保每个月份都显示(即使没有数据也要显示0) C. 计算的平均行(可能是基于月份数据计算的平均)&mdash;&mdash; 同样不需要连接日期表 但是,在原始SQL中,将月份数据和固定数据混合在一个结果集中,并通过rn字段来排序(rn可能是用来区分数据类型的,例如rn=1是年度数据,rn=2是月度数据,rn=3是平均数据)。 因此,我们保留这种结构,但需要修正数据不一致的问题。 具体修改步骤: 1. 在固定数据部分,将年月的格式统一为两位字符(对于月份数据)或者用其他方式标识(对于非月份数据,如'22年','23年','平均'等),这样在连接时就不会匹配到月份数据。 2. 在连接日期表的部分,我们使用LEFT JOIN,并且将日期表的月份格式转换为两位(即取后两位),这样就能和固定数据中的两位月份匹配。但是注意,固定数据中还有非两位的(如'22年'),所以不会匹配,这样LEFT JOIN就会为这些月份生成NULL,然后我们用COALESCE填充0?但这样不行,因为固定数据已经单独提供了,不需要连接日期表。 所以,实际上,我们不应该将固定数据和月份数据混在一个UNION ALL中再去连接日期表,而应该分开。 建议将查询拆分为: - 固定数据部分:直接UNION ALL,不连接日期表。 - 月份数据部分:使用日期表LEFT JOIN实际数据表(这里用td表示),这样确保每个月份都有数据(如果没有则显示0)。 - 平均数据部分:基于月份数据部分计算平均(或者单独计算)。 但是,原始SQL中已经将固定数据和月份数据都放在了一个子查询中,而且固定数据中已经包含了多个部分(包括年度和平均),所以我们需要明确每一部分的来源。 由于信息有限,我们只能根据现有代码进行修正,主要解决日期格式问题。 修正后的SQL框架: ```sql WITH dom AS ( -- 生成2025年各个月份,格式为'01','02',...,'12' SELECT RIGHT(CONVERT(VARCHAR(6), DATEADD(MONTH, number, '2025-01-01'), 112), 2) AS Month2 FROM master..spt_values WHERE type = 'P' AND number BETWEEN 0 AND 11 -- 确保只生成12个月 ) -- 缸体线数据(添加常量列) SELECT '缸体' AS 产线, rn, 年月, 不良类型, 不良数, 产量, 不良率 FROM ( -- 固定数据部分(非月度数据) SELECT '1' rn, '22年' AS 年月, '高压铸造' 不良类型, 83 不良数, 23564 产量, 0.10 不良率 UNION ALL SELECT '1', '23年', '高压铸造', 113, 31025, 0.16 UNION ALL SELECT '1', '24年', '高压铸造', 113, 31025, 0.141 UNION ALL SELECT '3', '平均', '高压铸造', 1, 31025, 0.0153 -- 月度数据部分:使用日期表左连接实际数据 UNION ALL SELECT '2' AS rn, dom.Month2 AS 年月, COALESCE(td.不良类型, '高压铸造') AS 不良类型, -- 如果实际表中没有数据,则用固定类型 COALESCE(td.不良数, 0) AS 不良数, COALESCE(td.产量, 0) AS 产量, -- 不良率:如果实际表中有则用,没有则0(注意实际表中不良率可能是百分比,也可能是小数,这里按原逻辑) COALESCE(td.不良率, 0) AS 不良率 FROM dom LEFT JOIN (...) td -- 实际数据表,需要确保其年月字段是两位月份 ON dom.Month2 = td.年月 -- 这里假设td表中的年月是两位字符串 -- 计算平均部分(基于月度数据计算的平均值)?但这里注意,上面的固定数据部分已经有一个平均行(rn=3),所以这里可能不需要再计算 -- 如果确实需要,可以单独计算,但要注意不要和固定数据中的平均行重复 ) AS 缸体源数据 ORDER BY rn, 年月; ``` 注意: 1. 在dom表中,我们直接生成两位的月份字符串('01'到'12')。 2. 在连接实际表td时,我们假设td表中的年月字段是两位字符串(如果不是,需要转换)。 3. 固定数据部分我们保留了非月份的数据(如'22年')和平均行(rn=3)。 4. 在月度数据部分,我们使用LEFT JOIN确保所有月份都出现,并用COALESCE填充05. 固定数据部分中的月度数据(如之前代码中的'01','04')现在被移到了实际数据表中?还是说仍然保留在固定数据部分?根据原始代码,固定数据部分有两条月度数据('01'和'04'),但这里我们不再放在固定数据部分,而是期望从实际表td中获取。如果实际表td中没有,那么需要将这两条数据插入到td表中,或者以其他方式加入。 但是,原始固定数据中还有两条月度数据: SELECT '2', '01', '高压铸造', 10, 0, 0.015 UNION ALL SELECT '2', '04', '高压铸造', 25, 0, 0.02 所以,我们有两种选择: a) 将这两条数据也放入实际表td中,这样在LEFT JOIN时就能获取到。 b) 将这两条数据作为固定月度数据,用UNION ALL加到月度数据部分之前,但是这样就不是从实际表获取了。 由于实际表td的结构未知,这里我们假设这两条数据必须从固定数据中来。那么我们可以将这两条数据单独作为固定月度数据,然后与日期表LEFT JOIN的结果合并?不行,因为日期表LEFT JOIN td表得到的是所有月份,而这两条数据是特定的两个月,我们不能重复。 所以,我们可能需要将这两条数据也纳入到实际数据中,即用一个子查询来模拟实际表td,这个子查询包括固定月度数据和从其他表查询的数据。 修改: 将固定月度数据与实际查询的数据合并成一个子查询,然后再与日期表左连接。 例如: ```sql UNION ALL SELECT '2' AS rn, dom.Month2 AS 年月, COALESCE(td.不良类型, '高压铸造') AS 不良类型, COALESCE(td.不良数, 0) AS 不良数, COALESCE(td.产量, 0) AS 产量, COALESCE(td.不良率, 0) AS 不良率 FROM dom LEFT JOIN ( -- 固定月度数据 SELECT '01' AS 年月, '高压铸造' 不良类型, 10 不良数, 0 产量, 0.015 不良率 UNION ALL SELECT '04' AS 年月, '高压铸造', 25, 0, 0.02 UNION ALL -- 实际查询的数据(从表中获取) SELECT ... ) td ON dom.Month2 = td.年月 ``` 这样,固定月度数据和实际查询的数据就合并成了td表,然后与日期表连接。 但是,这样处理会导致固定月度数据被重复?因为原始固定数据部分已经包含了这两条,现在又放到了td表中。所以我们需要将原始固定数据部分中的那两条月度数据去掉。 因此,修正后的固定数据部分只保留非月度数据(年度和平均),而将月度数据(不管是固定的还是动态的)都放到td表中。 最终,缸体源数据子查询变为: ```sql -- 固定数据部分(非月度数据) SELECT '1' rn, '22年' AS 年月, '高压铸造' 不良类型, 83 不良数, 23564 产量, 0.10 不良率 UNION ALL SELECT '1', '23年', '高压铸造', 113, 31025, 0.16 UNION ALL SELECT '1', '24年', '高压铸造', 113, 31025, 0.141 UNION ALL SELECT '3', '平均', '高压铸造', 1, 31025, 0.0153 -- 月度数据部分 UNION ALL SELECT '2' AS rn, dom.Month2 AS 年月, COALESCE(td.不良类型, '高压铸造') AS 不良类型, COALESCE(td.不良数, 0) AS 不良数, COALESCE(td.产量, 0) AS 产量, COALESCE(td.不良率, 0) AS 不良率 FROM dom LEFT JOIN ( -- 这里包括固定月度数据和从其他表查询的月度数据 SELECT '01' AS 年月, '高压铸造' 不良类型, 10 不良数, 0 产量, 0.015 不良率 UNION ALL SELECT '04' AS 年月, '高压铸造', 25, 0, 0.02 UNION ALL -- 从实际表中查询的月度数据(示例) SELECT RIGHT(年月, 2) AS 年月, -- 假设实际表中的年月是6位,我们取后两位 不良类型, 不良数, 产量, 不良率 FROM 实际表 WHERE 条件 ) td ON dom.Month2 = td.年月 ``` 这样,我们就保证了: - 固定非月度数据(年度、平均)直接显示 - 月度数据部分:通过日期表确保12个月份都有,并且将固定月度数据和实际表查询的数据合并后与日期表连接 关于计算平均部分,原始SQL中还有一个计算平均的UNION ALL: ```sql UNION ALL SELECT '2', '平均', '高压铸造', CONVERT(DECIMAL(12,0), 不良数)/5, CONVERT(DECIMAL(12,0), 合格数), CASE WHEN 合格数 = 0 THEN 0 ELSE CONVERT(DECIMAL(12,7), 不良数/合格数)*100 END FROM (...) ``` 注意,这个平均行在固定数据部分已经有一个(rn=3),所以这里可能是多余的?或者这个平均行是针对月度数据的平均?如果是,那么我们可以将其作为固定数据部分的一个单独行,但需要基于月度数据部分计算。 但是,这个平均行在原始代码中是UNION ALL在缸体源数据子查询中,而且rn='2',而固定数据部分已经有一个rn='3'的平均行。所以这里可能有两个平均行?这显然不合理。 因此,我们需要明确需求,究竟需要哪些平均行。 鉴于信息有限,我们暂时将这个平均行移除(因为原始需求不明确),或者将其注释掉,由用户决定。 最后,关于性能优化: 1. 使用CTE生成月份表是高效的,因为只有12行。 2. 在子查询中,将固定数据和动态数据分开,避免不必要的连接和转换。 3. 在LEFT JOIN中,使用COALESCE避免NULL值。 由于实际表查询部分(...)未知,我们无法进一步优化。 综上所述,修正后的SQL代码如下(注意:实际表查询部分仍用...表示,需要用户补充): ```sql WITH dom AS ( SELECT RIGHT(CONVERT(VARCHAR(6), DATEADD(MONTH, number, '2025-01-01'), 112), 2) AS Month2 FROM master..spt_values WHERE type = 'P' AND number BETWEEN 0 AND 11 ) SELECT '缸体' AS 产线, rn, 年月, 不良类型, 不良数, 产量, 不良率 FROM ( -- 固定数据部分(非月度数据:年度和平均) SELECT '1' rn, '22年' AS 年月, '高压铸造' 不良类型, 83 不良数, 23564 产量, 0.10 不良率 UNION ALL SELECT '1', '23年', '高压铸造', 113, 31025, 0.16 UNION ALL SELECT '1', '24年', '高压铸造', 113, 31025, 0.141 UNION ALL SELECT '3', '平均', '高压铸造', 1, 31025, 0.0153 -- 月度数据部分(确保12个月都有,包括0填充) UNION ALL SELECT '2' AS rn, dom.Month2 AS 年月, COALESCE(td.不良类型, '高压铸造') AS 不良类型, COALESCE(td.不良数, 0) AS 不良数, COALESCE(td.产量, 0) AS 产量, COALESCE(td.不良率, 0.000) AS 不良率 -- 注意:不良率可能是小数,用0.000填充 FROM dom LEFT JOIN ( -- 固定月度数据(示例中的两条) SELECT '01' AS 年月, '高压铸造' 不良类型, 10 不良数, 0 产量, 0.015 不良率 UNION ALL SELECT '04' AS 年月, '高压铸造', 25, 0, 0.02 UNION ALL -- 实际查询的月度数据(需要用户补充) -- 注意:这里的年月必须为两位字符串 SELECT CAST(MONTH(日期字段) AS VARCHAR(2)) AS 年月, -- 示例:如果日期字段是日期类型,取月份转换为两位字符串(注意:不足两位补0) 不良类型, 不良数, 产量, 不良率 FROM 实际表 WHERE 年份=2025 -- 或其他条件 ) td ON dom.Month2 = td.年月 ) AS 缸体源数据 ORDER BY rn, CASE WHEN rn='2' THEN 年月 ELSE '0' END; -- 注意:排序问题,对于非月度数据(rn不为2),年月不是数字,所以按字符串排序可能混乱,这里为了简单,将非月度数据排在前面(因为rn=1,3在2前面),而月度数据按年月排序 ``` 注意:排序部分做了调整,对于rn='2'(月度数据)按年月排序,其他rn按原顺序(因为rn=1和3)且年月是固定字符串,所以直接按rn和年月排序可能也能得到正确顺序,因为'22年'比'01'大,所以用了一个CASE将非月度数据的年月统一为'0',这样非月度数据就会排在前面(因为'0'<'01')。但是这样可能不够通用,另一种方式是分别排序: ```sql ORDER BY rn, CASE rn WHEN '1' THEN 1 WHEN '2' THEN 2 WHEN '3' THEN 3 ELSE 4 END, CASE WHEN rn='2' THEN 年月 ELSE '0' END ``` 但这里我们保持简单,因为原顺序中rn已经区分了顺序。 以上是对SQL的修正和优化。由于部分细节未知(如实际表结构),用户需要根据实际情况调整。 另外,关于原SQL中计算平均的部分(被注释掉的)如果需要,可以单独计算后再UNION ALL,但需要确保不重复。 最后,我们生成相关问题。 ### 相关问题 1. 在SQL中,如何生成一个日期序列(例如某年的所有月份)? 2. 使用`LEFT JOIN`时,如何用默认值替换`NULL`? 3. 在SQL查询中,如何将固定数据集(如常量值)与动态查询结果合并? 4. 在排序时,如何对不同类型的数据(如汇总行和详细数据行)进行分组排序? </think> ### SQL代码分析与优化 #### 问题分析 原始SQL存在以下关键问题: 1. **日期格式不匹配** CTE生成的日期格式为6位字符串(如`202501`),但固定数据中使用`01`/`04`等2位格式,导致连接失败 $$ \text{dom.DateOfMonth} \neq \text{td.年月} \implies \text{LEFT JOIN失效} $$ 2. **数据逻辑矛盾** - 固定数据中已包含`01`/`04`等月度数据(rn=2- 后续又通过`LEFT JOIN`连接相同月份数据,导致重复或冲突 3. **字段定义不一致** 平均计算部分引用不存在的`合格数`字段: ```sql SELECT '2', '平均', ... CONVERT(DECIMAL(12,0), 合格数) -- 但固定数据中无此字段 ``` 4. **排序规则缺陷** `ORDER BY rn, 年月`会导致非月份数据(如`22年`)与月份数据(`01`)混合排序 --- #### 优化方案 ```sql -- 1. 修正日期CTE:生成2位月份格式 WITH dom AS ( SELECT FORMAT(DATEADD(MONTH, number, '2025-01-01'), 'MM') AS Month2 -- 关键修正 FROM master..spt_values WHERE type = 'P' AND number BETWEEN 0 AND 11 -- 限制12个月 ), -- 2. 重构数据源:分离固定数据和动态数据 FixedData AS ( -- 非月度固定数据(年度/平均) SELECT '1' rn, '22年' AS 年月, '高压铸造' 不良类型, 83 不良数, 23564 产量, 0.10 不良率 UNION ALL SELECT '1', '23年', '高压铸造', 113, 31025, 0.16 UNION ALL SELECT '1', '24年', '高压铸造', 113, 31025, 0.141 UNION ALL SELECT '3', '平均', '高压铸造', 1, 31025, 0.0153 ), DynamicData AS ( -- 月度动态数据(连接日期表) SELECT '2' AS rn, dom.Month2 AS 年月, COALESCE(td.不良类型, '高压铸造') 不良类型, -- 空值保护 COALESCE(td.不良数, 0) 不良数, COALESCE(td.产量, 0) 产量, COALESCE(td.不良率, 0.0) 不良率 FROM dom LEFT JOIN (...) td -- 实际数据表 ON dom.Month2 = td.年月 -- 格式统一 ) -- 3. 组合结果集 SELECT '缸体' AS 产线, rn, 年月, 不良类型, 不良数, 产量, 不良率 FROM ( SELECT * FROM FixedData UNION ALL SELECT * FROM DynamicData ) AS CombinedData ORDER BY rn, CASE WHEN rn = '2' THEN 0 ELSE 1 END, -- 非月度数据优先 年月; -- 月度数据按月份排序 ``` #### 优化要点说明 1. **日期格式统一** - 使用`FORMAT(..., 'MM')`生成2位月份字符串 - 数学表达: $$ \text{Month2} = \{ m \mid m \in \{01,02,...,12\} \} $$ 2. **数据分层处理** ```mermaid graph TD A[原始数据] --> B[FixedData] A --> C[DynamicData] B --> D[非月度固定数据] C --> E[LEFT JOIN 日期表] D & E --> F[CombinedData] ``` 3. **空值处理机制** - `COALESCE`确保无数据月份显示0- 避免出现`NULL`破坏数据结构 4. **智能排序规则** - 非月度数据(rn≠2)优先显示 - 月度数据严格按月份排序 5. **性能优化** - CTE仅生成12行日期数据 - `UNION ALL`替代`UNION`避免去重开销[^3] - 限制`number BETWEEN 0 AND 11`减少扫描行数 --- #### 验证方法 ```sql -- 检查数据完整性 SELECT CASE WHEN 产线 <> '缸体' THEN '产线标识错误' WHEN rn='2' AND 年月 NOT IN ('01','02',...,'12') THEN '月份格式错误' WHEN 不良数 > 产量 THEN '逻辑矛盾' END AS ErrorType FROM 结果集 WHERE ErrorType IS NOT NULL ``` ### 相关问题 1. 如何在SQL Server中生成特定时间范围的日期序列?[^1][^4] 2. `COALESCE`和`ISNULL`函数在处理空值时有何区别? 3. 为什么在SQL中使用`UNION ALL`比`UNION`性能更好?[^2][^3] 4. 如何优化包含固定数据集和动态数据集的混合查询? 5. 在排序操作中如何处理混合数据类型(如年份和月份)?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值