SqlServer function 函数
SqlServer的数据库Tsql还是很强大,以此来纪念下表值函数的语法吧。
-- =============================================
-- Author: <jonney>
-- Create date: <2018.07.01>
-- Description: <根据产能、单机用料比例、班次、配送频率、提前期、最小包装数、欠品数、余料,等因素按时间点把料配送到产线>
-- =============================================
ALTER FUNCTION [dbo].[KittingItemCycleFn]
(
-- Add the parameters for the function here
@pWorkshop varchar(50) = '',-- 车间
@pDateStart varchar(50) = '',-- 计划开始日,开始
@pDateEnd varchar(50) = '',-- 计划开始日,结束
@pParentItem varchar(50) = '',-- 制品号
@pJon varchar(50) = '',-- Jon
@pWorkOrderNo varchar(50) = ''-- 工单号
)
RETURNS
@result TABLE
(
[Id] [int] NULL,
[WorkOrderNo] [varchar](50) NULL,
[ParentItem] [varchar](50) NULL,
[Jon] [varchar](50) NULL,
[Workshop] [varchar](50) NULL,
[StartDate] [varchar](50) NULL,
[CycleTime] [int] NULL,
[ItemNo] [varchar](50) NULL,
[Qty] [decimal](10, 2) NULL,
[QtyQp] [decimal](10, 2) NULL,
[ExtrNo] [varchar](50) NULL,
[Whs] [varchar](50) NULL,
[Keeper] [varchar](50) NULL
)
AS
BEGIN
-- Fill the table variable with the rows for your result set -- 若计划开始日期,开始为空,设置为今天
if (@pDateStart = '')
begin
set @pDateStart = DATEADD(DD, -1, GETDATE());
end; -- 若计划开始日期,结束为空,设置为明天
if (@pDateEnd = '')
begin
set @pDateEnd = DATEADD(DD, 1, GETDATE());
end; -- 声明返回的结果集
--declare @result dbo.KittingItem, @id int = 0;
declare @id int = 0; -- 声明一个游标,获取配料出库=6的出库单明细
/*
出库单据 = [SHLL]表
DSRD = 0 = 未作废
TYPE = 901 = 正常出库
[DESC] = 6 = JON配料出库
*/
declare kitItemRow cursor for
select b.ID, a.NO WorkOrderNo, a.ParentItem, a.Jon, a.Workshop, a.ExpectDate WorkStartDate, c.CODE ItemNo, b.ORDQ Qty, f.START_TIME, f.REQ_TYPE, f.QTY, f.XFER_NO
, g.CODE Whs, (select top 1 w.LBL from IUW z inner join [USER] w on z.USR=w.ID where z.DSRD=0 and z.WHS=a.WHS and z.ITM=b.ITM) Keeper
from [dbo].[SHPL] a inner join [dbo].[SHLL] b on a.ID = b.SHLO
inner join ITEM c on b.ITM = c.ID
inner join EREF d on b.ID = d.SHPL
inner join EXTR f on d.EXTR = f.XFER_NO
left join WRHS g on a.WHS = g.ID
where a.DSRD = 0 and a.TYPE=901 and a.[DESC]=6 and a.Workshop = @pWorkshop and a.ExpectDate between @pDateStart and @pDateEnd
and (@pParentItem = '' or a.ParentItem=@pParentItem)
and (@pJon = '' or charindex(@pJon, a.Jon) > 0)
and (@pWorkOrderNo = '' or a.NO = @pWorkOrderNo)
order by f.REQ_TYPE; -- 打开游标
open kitItemRow; -- 声明行变量,用于处理业务逻辑
declare @rId bigint, @rWorkOrderNo varchar(50), @rParentItem varchar(50), @rJon varchar(50), @rWorkshop varchar(50)
, @rWorkStartDate datetime, @rItemNo varchar(50), @rQty decimal(10, 2), @rWhs varchar(50), @rKeeper varchar(50); -- Imaps 数据信息
declare @shiftStart int, @reqType varchar(10), @qty decimal(10, 2), @extrNo varchar(50); -- 游标移动到下一行
fetch next from kitItemRow into @rId, @rWorkOrderNo, @rParentItem, @rJon, @rWorkshop, @rWorkStartDate, @rItemNo, @rQty, @shiftStart, @reqType, @qty , @extrNo, @rWhs, @rKeeper; -- 若移动游标后有数据,一直循环读取
WHILE (@@FETCH_STATUS =0)
begin
-- 班次特殊处理
set @shiftStart = @shiftStart / 100 -1; -- 对欠品的特殊处理
if @reqType = '' or @reqType = ''
begin
set @rQty = @qty; -- 将总的分配数量设置为欠品
end -- 获取部品的Cycle策略,若发货频率不等于0,则按照时间别(TYPE = 1602)配料
declare @moq int=0, @freq int=0, @preDeli int=0;-- 最小包装单位
select @moq=a.PARM1, @freq=a.PARM2, @preDeli=a.PARM3 from STRG a inner join ITEM b on a.ITM = b.ID where a.DSRD=0 and a.TYPE = 1602 and b.CODE = @rItemNo;
if @preDeli is not null -- 如果没有设置提前时间,则不考虑
begin
set @shiftStart -= @preDeli; -- 减掉提前发货小时
end; -- 声明 制品的满班产量、部品的单机用量
declare @cap int=0, @usage int=0;
select @usage=PARM1 from JITM where DSRD=0 and TYPE=2202 and MCHC = @rParentItem and ITMC= @rItemNo;-- 获取部品的单机用量TYPE=2202
select @cap=PARM1 from JITM where DSRD=0 and TYPE=2201 and MCHC = @rParentItem;-- 获取制品的满班产量TYPE=2201 declare @capItem int = @rQty;-- 当前部品的应发数量
declare @sendTimes int = 1; -- 发货次数
declare @itemSendQty int = @capItem / @sendTimes; -- 当前部品每次发货XX件 -- 发货频率、满班产量、单机用量都设置过,才考虑满班产量
if (@cap > 0 and @usage > 0 and @freq > 0)
begin
set @capItem = @cap * @usage;-- 当前部品的满班用量
set @sendTimes = 8 / @freq; -- 重新设置发货频率
set @itemSendQty = @capItem / @sendTimes; -- 当前部品每次发货XX件
end
else if (@freq > 0) -- 如果只设置了发货频率,那就只按照8除以发货频率来计算
begin
set @capItem = @rQty;
set @sendTimes = 8 / @freq; -- 重新设置发货频率
set @itemSendQty = @capItem / @sendTimes; -- 当前部品每次发货XX件
end
else -- 否则就按照集约类型,一次发完
begin
set @sendTimes = 1; -- 重新设置发货频率
set @itemSendQty = @rQty; -- 一次都发完
end -- 设置最迟配送时间
declare @lastTime int = @shiftStart + (@sendTimes - 1)*@freq;
-- 记录标准配送数量,有可能一次配送量超过标准的两次、多次
declare @standQty int = @itemSendQty;
-- 记录第几次配送
declare @curTime int=0; -- 判断最小包装数@moq
declare @modQty int=0;
if (@moq > 0)
begin
set @modQty = @itemSendQty % @moq;
if(@modQty > 0)
begin
set @itemSendQty = (@itemSendQty / @moq + 1) * @moq;
end
end -- 计算余料,放在第一次配送
declare @yuLiao int = 0;
set @yuLiao = @rQty - @itemSendQty * @sendTimes; -- 该行是否已经读取过欠品数据
declare @yijing int = 0;
declare @mpqQty int = @itemSendQty; -- 考虑过最小包装后的一次配送数 -- 以下处理配料情况,即Qty > 0
while @rQty > 0
begin
set @id += 1;--结果行号自增
set @curTime += 1;
set @rQty -= @itemSendQty; -- 若是第一次配料,且存在余料,就放在第一次配送
if(@yuLiao >0 and @curTime=1) set @rQty -= @yuLiao; -- 修正本次要配料数量
if @rQty < 0
begin
set @itemSendQty = @rQty + @itemSendQty;
end -- 判断是合并行,还是新建行
declare @existId int = 0;
select @existId = Id from @result where [WorkOrderNo]=@rWorkOrderNo and [ParentItem]=@rParentItem and [Jon]=@rJon and [ItemNo]=@rItemNo and [CycleTime]=@shiftStart if @reqType = '' or @reqType = ''
begin
-- 插入欠品数据
--if @existId > 0
--begin
-- update @result set QtyQp = QtyQp + @itemSendQty where Id=@existId;
--end
--else
if (@existId < 1)
begin
insert into @result(Id,[WorkOrderNo],[ParentItem],[Jon],[Workshop],[StartDate],[CycleTime],[ItemNo], Qty, [QtyQp], [ExtrNo], [Whs], [Keeper])
values(@Id, @rWorkOrderNo , @rParentItem , @rJon , @rWorkshop , convert(varchar(10),@rWorkStartDate,120), @shiftStart , @rItemNo , 0, case when (@yuLiao>0 and @curTime=1) then @itemSendQty + @yuLiao else @itemSendQty end, @extrNo, @rWhs, @rKeeper);
end
end
else if (@reqType = '')
begin
-- 插入配料信息
if @existId > 0
begin
update @result set Qty = Qty + @itemSendQty where Id=@existId;
end
else
begin
insert into @result(Id,[WorkOrderNo],[ParentItem],[Jon],[Workshop],[StartDate],[CycleTime],[ItemNo], Qty, [QtyQp], [ExtrNo], [Whs], [Keeper])
values(@Id, @rWorkOrderNo , @rParentItem , @rJon , @rWorkshop , convert(varchar(10),@rWorkStartDate,120), @shiftStart , @rItemNo , case when (@yuLiao>0 and @curTime=1) then @itemSendQty + @yuLiao else @itemSendQty end, 0, @extrNo, @rWhs, @rKeeper);
end -- 如果行剩余数<=0,再次从出库池获取欠品数据
if(@rQty <= 0)
begin
declare @temQp decimal = 0;-- 总欠品数
select @temQp = sum(QTY) from EXTR where ITEM_NO=@rItemNo and JON=@rJon and PARENT_ITEM_NO=@rParentItem and WS_CD=@rWorkshop and (REQ_TYPE=99 or REQ_TYPE=95)
if(@temQp > 0 and @yijing = 0)
begin
set @yijing = 1; -- 已经读取过一次的欠品不再读取
declare @temRqp int = 0; -- 本次操作的欠品数
set @temRqp = @mpqQty - @itemSendQty; -- 考虑MPQ后的配送数 - 当前行已配送数 = 当前行仍需欠品数
set @temQp -= @temRqp;
if(@temQp <= 0) set @temRqp += @temQp; -- 若已经到本班次最后一次配送,则全部配送完
if(@curTime >= @sendTimes)
begin
set @temRqp = @temQp;
set @temQp = 0;
end
update @result set QtyQp = @temRqp where Id = @id; -- 更新当前行的欠品数
set @shiftStart += (@temRqp + @itemSendQty) / @standQty * @freq; -- 修改下次配送时点 while(@temQp > 0) -- 持续把欠品数分配完
begin
set @temRqp = @mpqQty;
if(@shiftStart >= @lastTime) -- 若到最后一次配送时点,则把剩余欠品全部计算
begin
set @shiftStart = @lastTime;
set @temRqp = @temQp;
set @temQp = 0;
end
else set @temQp -= @temRqp;
if(@temQp <= 0) set @temRqp += @temQp;
set @id += 1; -- 插入下一个配送时点的欠品数据
insert into @result(Id,[WorkOrderNo],[ParentItem],[Jon],[Workshop],[StartDate],[CycleTime],[ItemNo], Qty, [QtyQp], [ExtrNo], [Whs], [Keeper])
values(@Id, @rWorkOrderNo , @rParentItem , @rJon , @rWorkshop , convert(varchar(10),@rWorkStartDate,120), @shiftStart , @rItemNo , 0, @temRqp, @extrNo, @rWhs, @rKeeper);
set @shiftStart += @temRqp / @standQty * @freq; -- 更新配送时点
end
end
end
end -- 发货时间点增加
set @shiftStart += @itemSendQty / @standQty * @freq;
if @shiftStart >= 24
begin
set @shiftStart %= 24;
set @rWorkStartDate = DATEADD(DAY, 1, @rWorkStartDate)
end
end -- 获取下一行
fetch next from kitItemRow into @rId, @rWorkOrderNo, @rParentItem, @rJon, @rWorkshop, @rWorkStartDate, @rItemNo, @rQty, @shiftStart, @reqType, @qty , @extrNo, @rWhs, @rKeeper;
end -- 关闭游标
close kitItemRow;
-- 释放游标
DEALLOCATE kitItemRow; -- 返回结果
--SELECT [WorkOrderNo], [ParentItem], [Jon], [Workshop], [StartDate], [CycleTime], [ItemNo], [Qty], [QtyQp], [Keeper], [Whs] from @result
--where qty>0 and qtyqp > 0
--group by [ParentItem],[Jon],[Workshop],[StartDate],[CycleTime],[ItemNo]
--order by [StartDate],[CycleTime], WorkOrderNo, [ItemNo];
RETURN
END
SqlServer function 函数的更多相关文章
- sqlserver自定义函数的创建与调用
sqlserver中有系统提供的函数,像avg.sum.getdate()等,用户还可以自定义函数. 用户自定义的函数包括:标量函数和表值函数,其中标量函数和系统函数的用法一样,表值函数根据主体的定义 ...
- 2019-2-14SQLserver中function函数和存储过程、触发器、CURSOR
Sqlserver 自定义函数 Function使用介绍 前言: 在SQL server中不仅可以可以使用系统自带的函数(时间函数.聚合函数.字符串函数等等),还可以根据需要自定义函数 ...
- 使用sqlserver日期函数获取当前日期
使用sqlserver日期函数中的getdate()可以获取当现的日期,下面就将为您介绍这种使用sqlserver日期函数获取当前日期的方法,供您参考,希望对您学习sqlserver日期函数有所启迪. ...
- sqlserver自定义函数【粘】
用户定义自定义函数像内置函数一样返回标量值,也可以将结果集用表格变量返回 用户自定义函数的类型: 标量函数:返回一个标量值 表格值函数{内联表格值函数.多表格值函数}:返回行集(即返回多个值) 1. ...
- 关于Function()函数对象的那些小九九
概念:首先,函数是一种特殊类型的数据,函数也是数据类型的一种,实际上函数也是一种对象,函数对象的内建构造器是Function(); 函数的几种创建方式: 函数声明法: function sum(a,b ...
- JavaScript function函数种类(转)
转自:http://www.cnblogs.com/polk6/p/3284839.html JavaScript function函数种类 本篇主要介绍普通函数.匿名函数.闭包函数 目录 1. 普通 ...
- JavaScript function函数种类介绍
JavaScript function函数种类介绍 本篇主要介绍普通函数.匿名函数.闭包函数 1.普通函数介绍 1.1 示例 ? 1 2 3 function ShowName(name) { ...
- 【JS学习笔记】关于function函数
函数的基本格式 function 函数名() { 代码: } 函数的定义和调用 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transit ...
- sqlserver自定义函数
标量函数 RETURNS 子句指定一种标量数据类型,则函数为标量值函数. 语法 Create function 函数名(参数) Returns 返回值数据类型 [with {Encryption | ...
随机推荐
- Slq怎么样获取首条记录和最后一条记录
sql如何查询表的第一条记录和最后一条记录 方法一:使用top select TOP 1 * from apple;TOP 1 表示表apple中的第一条数据 select TOP 1 * from ...
- AOP原理解析及Castle、Autofac、Unity框架使用
转自:https://www.cnblogs.com/neverc/p/5241466.html AOP介绍 面向切面编程(Aspect Oriented Programming,英文缩写为AOP), ...
- QQ浏览器兼容模式下Cookie失效 导致的NetCore Cookie认证失效
最近在写NetCore项目采用的是NetCore的Cookie认证.结果偶然发现QQ浏览器登录不好用.这里先需要了解一下set-cookie中的SameSite属性 导致原因 首先Fiddler 4 ...
- db事务级别及锁
相关sql 事务A BEGIN TRANSACTION --执行修改 获取排他锁 UPDATE Product SET Price = 10 WHERE Id = 1 --阶段2 UPDATE Pro ...
- Centos7 中使用搭建devpi并且使用Supervisor守护进程
一.先介绍一下supervisor 1.安装supervisor 使用yum安装或者使用pip安装都可以,使用yum安装的相对简单一些,并且不用拷贝一份 supervisord.conf 的配置文件, ...
- python3入门之集合set
之前介绍python的数据结构时,没有介绍set(集合)现在在这里稍微介绍下: set原理 Python 还 包 含 了 一 个 数 据 类 型-- set ( 集 合 ) . 集 合 是 一 个 无 ...
- leetcode-788-Rotated Digits(使用vector替代if else的逐个判断)
题目描述: X is a good number if after rotating each digit individually by 180 degrees, we get a valid nu ...
- C#-函数的传值与传址
传值就是将实参的值传到所调用的函数里面,实参的值并没有发生变化,默认传值的有int型,浮点型,bool型,char字符型,结构体等等. 传址就是将地址传到所调用的函数里面操作,实参的值也会跟着变化,传 ...
- excel2010冻结行列
https://jingyan.baidu.com/article/a24b33cd56f6bd19ff002b7c.html
- GPUImage处理图片(滤镜)
GPUImage 是基于 GPU 处理图像的一个开源库, 提供了各种图像处理滤镜,例如调 亮度/饱和度/曝光度/白平衡/锐化等滤镜. 并且支持照相机/摄像机 的实时滤镜. GPUImage采用链式方式 ...