Foxtable(狐表)用户栏目专家坐堂 → SQL中遍历表每行计算应该如何实现效率才高?


  共有2299人关注过本帖树形打印复制链接

主题:SQL中遍历表每行计算应该如何实现效率才高?

帅哥哟,离线,有人找我吗?
happyft
  1楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:八尾狐 帖子:1926 积分:17403 威望:0 精华:0 注册:2014/7/29 19:09:00
SQL中遍历表每行计算应该如何实现效率才高?  发帖心情 Post By:2017/12/20 17:19:00 [只看该作者]

在MRP每层计算后会得到如下的一个需求表MPS03,然后必须对此表每行进行计算得到计划产出及可用库存


图片点击可在新窗口打开查看此主题相关图片如下:mrp计算.png
图片点击可在新窗口打开查看

计算逻辑是这样的,
1 将所有产品按编码及需求日期排序,这样相同的产品就会排在一起,每种产品日期最前的为第一行
2 用第一行的需求数量-期初库存-预计入库 得到净需求
3 如果净需求>0 ,则会根据  (净需求/批量)取整*批量 得到 计划产出 数量, 计划产出-净需求 = 可用库存
   如果净需求 <=0 则 可用库存 = 期初库存=预计入库
4 将相同产品编码本行的可用库存 赋值给下一行的期初库存 开始按上面的方式进行下一行计算,直到全部完成为止

按上述逻辑如果用sql游标大概如下,有些地方不知道怎么写?而且这种效率很胝.
Declare @Pcode NVARCHAR(20),
@date DATE;
Declare mycur CURSOR For S elect 产品编码,需求日期 FROM MPS03 ORDER BY 产品编码,需求日期;
OPEN mycur;
FETCH Next FROM mycur
INTO @Pcode,
@date;
While (@@FETCH_STATUS = 0)
    BEGIN
    UPDATE MPS03
    S ET 净需求 = 需求数量-期初库存-预计入库 WHERE 产品编码 = @Pcode And 需求日期 = @date
    UPDATE MPS03
    S ET 计划产出 = CEILING(净需求/批量)*批量 WHERE 产品编码 = @Pcode And 需求日期 = @date And 净需求 > 0
    UPDATE MPS03
    S ET 可用库存 = 计划产出-净需求 WHERE 产品编码 = @Pcode And 需求日期 = @date And 计划产出 > 0
    UPDATE MPS03
    S ET 同种产品下一行的期初库存 = 本行的可用库存
    END;
    CLOSE mycur;
    DEALLOCATE mycur

上表数据大概有近万行,整个sql的语句应该怎么写?

谢谢!




 回到顶部
帅哥哟,离线,有人找我吗?
有点甜
  2楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:版主 帖子:85326 积分:427815 威望:0 精华:5 注册:2012/10/18 22:13:00
  发帖心情 Post By:2017/12/20 17:35:00 [只看该作者]

呃,有必要这样处理吗?你这种,基本都是用查询、子查询直接得到计算结果的。

 

如果要更新,同样用update语句直接查询和更新。

 

看看sqlserver流水账的设计 https://www.baidu.com/baidu?wd=sqlserver+%E6%B5%81%E6%B0%B4%E8%B4%A6

 


 回到顶部
帅哥哟,离线,有人找我吗?
HappyFt
  3楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:八尾狐 帖子:1926 积分:17403 威望:0 精华:0 注册:2014/7/29 19:09:00
  发帖心情 Post By:2017/12/20 19:52:00 [只看该作者]

按流水帐那样不行啊,因为每行中的净需求,可用库存,计划产出都是要逐行计算得出,而且还有条件
如果是加载到foxtable中循环每行来处理我是可以,类似下面这样的

Dim drs As List(of DataRow) = DataTables("MRP物料需求").Select("", "物料代码, 计划开始")
drs(0)("需求累计") = drs(0)("需求数量")
For i As Integer = 1 To drs.Count - 1
    If drs(i)("物料代码") = drs(i - 1)("物料代码") Then
        drs(i)("需求累计") = drs(i-1)("需求累计") + drs(i)("需求数量")
    Else
        drs(i)("需求累计") = drs(i)("需求数量")
    End If
Next

但我这部份的代码只是储存过程中的一小部份,只能在sql中处理,按1楼的处理逻辑老师帮忙看下具体怎么写?
谢谢了!


 回到顶部
帅哥哟,离线,有人找我吗?
有点甜
  4楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:版主 帖子:85326 积分:427815 威望:0 精华:5 注册:2012/10/18 22:13:00
  发帖心情 Post By:2017/12/20 20:12:00 [只看该作者]

 你需要的就是流水账的查询语句,比如,可以简化成这样

 

https://www.cnblogs.com/Fooo/p/4070030.html

 


 回到顶部
帅哥哟,离线,有人找我吗?
HappyFt
  5楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:八尾狐 帖子:1926 积分:17403 威望:0 精华:0 注册:2014/7/29 19:09:00
  发帖心情 Post By:2017/12/20 22:04:00 [只看该作者]

SE LECT t.产品编码,
    t.需求日期,
    t.需求数量,
    t.期初库存,
    (
        SE LECT TOP 1
            期初库存
        FROM MPS03
        WHERE 产品编码 = t.产品编码
              AND 需求日期 < t.需求日期
        ORDER BY 产品编码,
            需求日期 DESC
    ) AS 可用库存
FROM MPS03 t
ORDER BY t.产品编码,
    t.需求日期;


此主题相关图片如下:mrp计算2.png
按此在新窗口浏览图片


上面查询的结果每种产品编码的第一行的可用库存被变成NUll了,
要求第一行的可用库存保留原值,从第二行开始才提取第一行的期初库存,上面的sql语句要如何写才能一次完成?

还有另外一个问题就是,update的问题,每行都要根据上面一行计算得出的可用库存才能再计算本行的相关数据,这样
UPDATE MPS03
    S ET 净需求 = 需求数量-期初库存-预计入库 WHERE 条件 产品编码 = t1.产品编码 And 需求日期 = @date
    UPDATE MPS03
    S ET 计划产出 = CEILING(净需求/批量)*批量 WHERE 产品编码 = @Pcode And 需求日期 = @date And 净需求 > 0
    UPDATE MPS03
    S ET 可用库存 = 计划产出-净需求 WHERE 产品编码 = @Pcode And 需求日期 = @date And 计划产出 > 0
    UPDATE MPS03

等上面的语句不变成每行都要执行一次,要如何写才像查询那样一次就可以完成update?



 回到顶部
帅哥哟,离线,有人找我吗?
有点甜
  6楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:版主 帖子:85326 积分:427815 威望:0 精华:5 注册:2012/10/18 22:13:00
  发帖心情 Post By:2017/12/20 22:33:00 [只看该作者]

1、可用库存是需要计算求出的,不是取第一行的数据,就好像流水账那样,计算余额

 

https://www.cnblogs.com/Fooo/p/4070030.html

 

2、既然能够select出数据了,那update就一句语句即可

 

3、不会做就上传测试实例。


 回到顶部
帅哥哟,离线,有人找我吗?
HappyFt
  7楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:八尾狐 帖子:1926 积分:17403 威望:0 精华:0 注册:2014/7/29 19:09:00
  发帖心情 Post By:2017/12/21 18:34:00 [只看该作者]

 下载信息  [文件大小:   下载次数: ]
点击浏览该文件:mps03.rar


真的不知道怎么写,  我上传了生成测试表MPS03及其数据的脚本,麻烦老师看怎么写把sql语句贴出来就可以,

计算逻辑是这样的,
1 将所有产品按编码及需求日期排序,这样相同的产品就会排在一起,每种产品日期最前的为第一行
2 每一个产品编码从其需求日期最小的那一行开始: 
    净需求=需求数量+预计出库-期初库存-预计入库
3 计算可用库存
   如果净需求>0 ,则  
   计划产出 = (净需求/批量)取整*批量 ;
   可用库存 = 计划产出-净需求 
   如果净需求 <=0 则 可用库存 = -净需求(即净需求计算=-20 则可用库存就=20)
4 将计算得到的 可用库存作为下一行的期初库存  重复2,3,4步骤直到全部完成为止

谢谢老师了!

 回到顶部
帅哥哟,离线,有人找我吗?
有点甜
  8楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:版主 帖子:85326 积分:427815 威望:0 精华:5 注册:2012/10/18 22:13:00
  发帖心情 Post By:2017/12/21 23:07:00 [只看该作者]

测试了一下,没有变通方法,必须一行一行计算,如

 

declare m_cursor cursor scroll for
select 产品编码,需求日期 from MPS03 ORDER BY 产品编码,需求日期
for update
-- 打开游标
open m_cursor
declare   @bm varchar(50), @date date, @kykc float, @pbm varchar(50)
--填充数据
fetch next from m_cursor into @bm, @date
--假如检索到了数据,才处理
while @@FETCH_STATUS=0
begin
    if @bm = @pbm
        UPDATE MPS03 SET 期初库存=@kykc,净需求=需求数量+预计出库-期初库存-预计入库,计划产出=case when 需求数量+预计出库-期初库存-预计入库 > 0 then CEILING((需求数量+预计出库-期初库存-预计入库)/批量)*批量 else 0 end, 可用库存=(case when 需求数量+预计出库-期初库存-预计入库 > 0 then CEILING((需求数量+预计出库-期初库存-预计入库)/批量)*批量 else 0 end)-(需求数量+预计出库-期初库存-预计入库) WHERE current of m_cursor
    else
  UPDATE MPS03 SET 净需求=需求数量+预计出库-期初库存-预计入库,计划产出=case when 需求数量+预计出库-期初库存-预计入库 > 0 then CEILING((需求数量+预计出库-期初库存-预计入库)/批量)*批量 else 0 end, 可用库存=(case when 需求数量+预计出库-期初库存-预计入库 > 0 then CEILING((需求数量+预计出库-期初库存-预计入库)/批量)*批量 else 0 end)-(需求数量+预计出库-期初库存-预计入库) WHERE current of m_cursor
    update mps03 set @kykc = 可用库存 WHERE current of m_cursor
    --填充下一条数据
    set @pbm = @bm
   
    fetch next from m_cursor into @bm, @date
end
-- 关闭游标
close m_cursor
--释放游标
deallocate m_cursor

select * from MPS03 ORDER BY 产品编码,需求日期

[此贴子已经被作者于2017/12/22 8:53:31编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
HappyFt
  9楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:八尾狐 帖子:1926 积分:17403 威望:0 精华:0 注册:2014/7/29 19:09:00
  发帖心情 Post By:2017/12/21 23:58:00 [只看该作者]

谢谢老师了,这么晚还在回帖,看来只能用游标了,我试试看,不知道要运行多长时间,因为每次计算差不多有5层,像这样的表至少要运算5次,其他代码到是每层只用十几秒左右,谢谢

 回到顶部
帅哥哟,离线,有人找我吗?
HappyFt
  10楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:八尾狐 帖子:1926 积分:17403 威望:0 精华:0 注册:2014/7/29 19:09:00
  发帖心情 Post By:2017/12/22 0:04:00 [只看该作者]

我测试了下才两秒钟就执行完了,为什么这么快?谢谢了

 回到顶部
总数 11 1 2 下一页