Files
JY1.0/生产计划SQL开发文档.md
2026-05-21 09:46:02 +08:00

9.9 KiB
Raw Blame History

车间生产管理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"
}