# **车间生产管理SQL开发 - 逐步构建生产计划视图与存储过程** ## **1. 原始需求与基础查询** **目标**:从多个关联表中查询生产数据,并逐步添加计算字段。 ### **1.1 基础数据源** 涉及三张核心表和视图: - `车间生产管理_零件工序_视图`:包含订单号、产品名称、零件名称、工序、数量等。 - `车间生产管理工艺_零件工序_任务分配`:包含工序流水号、计划数量、加工数量、计划日期等。 - `基础数据_设备工位点检表`:包含设备流水号、工位号、设备名称。 ### **1.2 初始联接查询** 通过 `工序流水号` 和 `设备流水号` 联接上述三张表。 sql ``` SELECT dbo.车间生产管理_零件工序_视图.订单号, dbo.车间生产管理_零件工序_视图.产品名称, -- ... 其他字段 dbo.基础数据_设备工位点检表.工位号 + N':' + dbo.基础数据_设备工位点检表.设备名称 AS 设备, dbo.车间生产管理_零件工序_视图.数量 AS 订单数, dbo.车间生产管理工艺_零件工序_任务分配.数量 AS 计划数 -- ... 其他字段 FROM dbo.车间生产管理工艺_零件工序_任务分配 INNER JOIN dbo.车间生产管理_零件工序_视图 ON dbo.车间生产管理工艺_零件工序_任务分配.工序流水号 = dbo.车间生产管理_零件工序_视图.工序流水号 INNER JOIN dbo.基础数据_设备工位点检表 ON dbo.车间生产管理工艺_零件工序_任务分配.设备流水号 = dbo.基础数据_设备工位点检表.设备流水号 ``` ## **2. 逐步新增计算字段** 在基础查询上,根据业务需求分步添加了三个计算字段。 ### **2.1 新增 `状态` 字段** **需求**:根据加工数量与计划数量的对比,判断订单状态为“派工中”、“生产中”或“已完成”。 **逻辑**: - **已完成**:加工数量 >= 计划数量 - **生产中**:0 < 加工数量 < 计划数量 - **派工中**:加工数量 = 0 或 NULL **SQL 片段**: sql ``` CASE WHEN ISNULL(dbo.车间生产管理工艺_零件工序_任务分配.加工数量, 0) >= dbo.车间生产管理工艺_零件工序_任务分配.数量 THEN '已完成' WHEN ISNULL(dbo.车间生产管理工艺_零件工序_任务分配.加工数量, 0) > 0 AND ISNULL(dbo.车间生产管理工艺_零件工序_任务分配.加工数量, 0) < dbo.车间生产管理工艺_零件工序_任务分配.数量 THEN '生产中' ELSE '派工中' END AS 状态 ``` ### **2.2 新增 `完成率` 字段** **需求**:计算完成率 = (加工数量 / 计划数量) × 100%。 **SQL 片段**: sql ``` CASE WHEN ISNULL(dbo.车间生产管理工艺_零件工序_任务分配.数量, 0) = 0 THEN '0%' ELSE CAST(ROUND(ISNULL(dbo.车间生产管理工艺_零件工序_任务分配.加工数量, 0) * 100.0 / dbo.车间生产管理工艺_零件工序_任务分配.数量, 2) AS DECIMAL(10, 2)) + '%' END AS 完成率 ``` ### **2.3 新增 `投产时间` 字段** **需求**:从 `车间生产管理工艺_零件工艺计划` 表获取 `分配日期`,作为投产时间。 **实现**:需要 `LEFT JOIN` 新表,通过 `工艺计划流水号` 关联。 sql ``` -- 新增的 JOIN LEFT OUTER JOIN dbo.车间生产管理工艺_零件工艺计划 ON dbo.车间生产管理_零件工序_视图.工艺计划流水号 = dbo.车间生产管理工艺_零件工艺计划.工艺计划流水号 -- 新增字段 CONVERT(varchar(10), dbo.车间生产管理工艺_零件工艺计划.分配日期, 23) AS 投产时间 ``` ## **3. 创建生产计划视图 (`车间生产管理_生产计划_视图_新`)** 将上述所有逻辑整合,创建了一个名为 `车间生产管理_生产计划_视图_新` 的视图。 sql ``` CREATE VIEW dbo.车间生产管理_生产计划_视图_新 AS SELECT dbo.车间生产管理_零件工序_视图.订单号, dbo.车间生产管理_零件工序_视图.产品名称, dbo.车间生产管理_零件工序_视图.零件名称, dbo.车间生产管理_零件工序_视图.工序, dbo.基础数据_设备工位点检表.工位号 + N':' + dbo.基础数据_设备工位点检表.设备名称 AS 设备, dbo.车间生产管理_零件工序_视图.数量 AS 订单数, dbo.车间生产管理工艺_零件工序_任务分配.数量 AS 计划数, CONVERT(varchar(10), dbo.车间生产管理工艺_零件工序_任务分配.计划完成日期, 23) AS 计划完成日期, dbo.车间生产管理工艺_零件工序_任务分配.数量 - dbo.车间生产管理工艺_零件工序_任务分配.加工数量 AS 剩余数, dbo.车间生产管理_零件工序_视图.零件图号, dbo.车间生产管理_零件工序_视图.工序顺序, CONVERT(varchar(10), dbo.车间生产管理工艺_零件工序_任务分配.计划开始日期, 23) AS 计划开始日期, dbo.基础数据_设备工位点检表.设备名称, -- 状态字段 CASE WHEN ISNULL(dbo.车间生产管理工艺_零件工序_任务分配.加工数量, 0) >= dbo.车间生产管理工艺_零件工序_任务分配.数量 THEN '已完成' WHEN ISNULL(dbo.车间生产管理工艺_零件工序_任务分配.加工数量, 0) > 0 AND ISNULL(dbo.车间生产管理工艺_零件工序_任务分配.加工数量, 0) < dbo.车间生产管理工艺_零件工序_任务分配.数量 THEN '生产中' ELSE '派工中' END AS 状态, -- 完成率字段 CASE WHEN ISNULL(dbo.车间生产管理工艺_零件工序_任务分配.数量, 0) = 0 THEN '0%' ELSE CAST(ROUND(ISNULL(dbo.车间生产管理工艺_零件工序_任务分配.加工数量, 0) * 100.0 / dbo.车间生产管理工艺_零件工序_任务分配.数量, 2) AS DECIMAL(10, 2)) + '%' END AS 完成率, CONVERT(varchar(10), dbo.车间生产管理工艺_零件工艺计划.分配日期, 23) AS 投产时间, dbo.车间生产管理_零件工序_视图.精工期限 FROM dbo.车间生产管理工艺_零件工序_任务分配 INNER JOIN dbo.车间生产管理_零件工序_视图 ON dbo.车间生产管理工艺_零件工序_任务分配.工序流水号 = dbo.车间生产管理_零件工序_视图.工序流水号 INNER JOIN dbo.基础数据_设备工位点检表 ON dbo.车间生产管理工艺_零件工序_任务分配.设备流水号 = dbo.基础数据_设备工位点检表.设备流水号 LEFT OUTER JOIN dbo.车间生产管理工艺_零件工艺计划 ON dbo.车间生产管理_零件工序_视图.工艺计划流水号 = dbo.车间生产管理工艺_零件工艺计划.工艺计划流水号 ``` ### **4. 视图创建后的关键Bug与修复** #### **4.1 Bug #1:查询视图时“varchar转换为numeric”错误** **原因**:在计算`完成率`字段时,错误地将数字(DECIMAL)与字符串('%')直接拼接,SQL Server无法自动处理类型转换。\ **修复**:将计算得到的数字显式转换为字符串(VARCHAR)后再拼接。 sql ``` -- 错误写法 CAST(... AS DECIMAL(10, 2)) + '%' -- 正确写法 CAST(CAST(... AS DECIMAL(10, 2)) AS VARCHAR(20)) + '%' ``` #### **4.2 Bug #2:存储过程中“列名‘年份’无效”和“modulo运算符不兼容”** **原因**: 1. 最初假设视图包含`年份`和`月份`字段,但实际视图不包含,导致筛选失败。 2. 动态SQL中拼接`LIKE`子句时,单引号处理混乱,导致SQL Server将部分字符串和`%`误解析为模运算。 **最终修复**: 1. **利用已有字段筛选**:使用视图中的`投产时间`字段进行模糊匹配。 sql ``` -- 动态SQL中的WHERE部分 WHERE (投产时间 like @月份 + '-%' or 计划完成日期 like @月份 + '-%') ``` 2. **正确拼接动态SQL**:确保参数化查询,避免字符串拼接错误。 sql ``` -- 存储过程中正确的拼接和参数传递示例 ALTER PROCEDURE [dbo].[车间生产管理_生产计划_查询数据] @月份 nvarchar(50), @零件名称_check bit = null, @零件名称 nvarchar(50) = null, @状态_check bit = null, @状态 nvarchar(50) = null AS BEGIN DECLARE @selectStr NVARCHAR(4000) = 'SELECT * FROM 车间生产管理_生产计划_视图_新 WHERE (投产时间 like @月份 + ''-%'' or 计划完成日期 like @月份 + ''-%'')'; IF @零件名称_check = 1 SET @selectStr = @selectStr + ' AND 零件名称 like ''%'' + @零件名称 + ''%'''; IF @状态_check = 1 SET @selectStr = @selectStr + ' AND 状态 = @状态'; EXEC sp_executesql @selectStr, N'@月份 nvarchar(50), @零件名称 nvarchar(50), @状态 nvarchar(50)', @月份, @零件_name, @状态; END ``` ### **5. 新增 `年` 和 `月` 字段** 为方便按年月筛选,在最终视图中从`投产时间`(分配日期)中直接提取`年`和`月`两个独立字段。 **最终视图SQL(含年、月字段)**: sql ``` SELECT -- ... 其他字段 ... CASE WHEN dbo.车间生产管理工艺_零件工艺计划.分配日期 IS NOT NULL THEN YEAR(dbo.车间生产管理工艺_零件工艺计划.分配日期) ELSE NULL END AS 年, CASE WHEN dbo.车间生产管理工艺_零件工艺计划.分配日期 IS NOT NULL THEN MONTH(dbo.车间生产管理工艺_零件工艺计划.分配日期) ELSE NULL END AS 月 FROM -- ... 表联接 ... ``` 这样存储过程可直接使用`WHERE 年 = @年 AND 月 = @月`进行筛选,更为高效。 ### **6. 最终调用示例** 在应用程序中调用存储过程,传入参数。 json ``` { "合同编号": "", "合同编号_check": 0, "零件名称_check": 0, "零件名称": "", "产品名称_check": 0, "产品名称": "", "状态_check": 0, "状态": "", "月份": "2025-04" } ```