SqlServer的數據庫Tsql還是很強大,以此來紀念下表值函數的語法吧。
1 -- ============================================= 2 -- Author: <jonney> 3 -- Create date: <2018.07.01> 4 -- Description: <根據產能、單機用料比例、班次、配送頻率、提前期、最小包裝數、欠品數、余料,等因素按時間點把料配送到產線> 5 -- ============================================= 6 ALTER FUNCTION [dbo].[KittingItemCycleFn] 7 ( 8 -- Add the parameters for the function here 9 @pWorkshop varchar(50) = '',-- 車間 10 @pDateStart varchar(50) = '',-- 計划開始日,開始 11 @pDateEnd varchar(50) = '',-- 計划開始日,結束 12 @pParentItem varchar(50) = '',-- 制品號 13 @pJon varchar(50) = '',-- Jon 14 @pWorkOrderNo varchar(50) = ''-- 工單號 15 ) 16 RETURNS 17 @result TABLE 18 ( 19 [Id] [int] NULL, 20 [WorkOrderNo] [varchar](50) NULL, 21 [ParentItem] [varchar](50) NULL, 22 [Jon] [varchar](50) NULL, 23 [Workshop] [varchar](50) NULL, 24 [StartDate] [varchar](50) NULL, 25 [CycleTime] [int] NULL, 26 [ItemNo] [varchar](50) NULL, 27 [Qty] [decimal](10, 2) NULL, 28 [QtyQp] [decimal](10, 2) NULL, 29 [ExtrNo] [varchar](50) NULL, 30 [Whs] [varchar](50) NULL, 31 [Keeper] [varchar](50) NULL 32 ) 33 AS 34 BEGIN 35 -- Fill the table variable with the rows for your result set 36 37 -- 若計划開始日期,開始為空,設置為今天 38 if (@pDateStart = '') 39 begin 40 set @pDateStart = DATEADD(DD, -1, GETDATE()); 41 end; 42 43 -- 若計划開始日期,結束為空,設置為明天 44 if (@pDateEnd = '') 45 begin 46 set @pDateEnd = DATEADD(DD, 1, GETDATE()); 47 end; 48 49 -- 聲明返回的結果集 50 --declare @result dbo.KittingItem, @id int = 0; 51 declare @id int = 0; 52 53 -- 聲明一個游標,獲取配料出庫=6的出庫單明細 54 /* 55 出庫單據 = [SHLL]表 56 DSRD = 0 = 未作廢 57 TYPE = 901 = 正常出庫 58 [DESC] = 6 = JON配料出庫 59 */ 60 declare kitItemRow cursor for 61 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 62 , 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 63 from [dbo].[SHPL] a inner join [dbo].[SHLL] b on a.ID = b.SHLO 64 inner join ITEM c on b.ITM = c.ID 65 inner join EREF d on b.ID = d.SHPL 66 inner join EXTR f on d.EXTR = f.XFER_NO 67 left join WRHS g on a.WHS = g.ID 68 where a.DSRD = 0 and a.TYPE=901 and a.[DESC]=6 and a.Workshop = @pWorkshop and a.ExpectDate between @pDateStart and @pDateEnd 69 and (@pParentItem = '' or a.ParentItem=@pParentItem) 70 and (@pJon = '' or charindex(@pJon, a.Jon) > 0) 71 and (@pWorkOrderNo = '' or a.NO = @pWorkOrderNo) 72 order by f.REQ_TYPE; 73 74 -- 打開游標 75 open kitItemRow; 76 77 -- 聲明行變量,用於處理業務邏輯 78 declare @rId bigint, @rWorkOrderNo varchar(50), @rParentItem varchar(50), @rJon varchar(50), @rWorkshop varchar(50) 79 , @rWorkStartDate datetime, @rItemNo varchar(50), @rQty decimal(10, 2), @rWhs varchar(50), @rKeeper varchar(50); 80 81 -- Imaps 數據信息 82 declare @shiftStart int, @reqType varchar(10), @qty decimal(10, 2), @extrNo varchar(50); 83 84 -- 游標移動到下一行 85 fetch next from kitItemRow into @rId, @rWorkOrderNo, @rParentItem, @rJon, @rWorkshop, @rWorkStartDate, @rItemNo, @rQty, @shiftStart, @reqType, @qty , @extrNo, @rWhs, @rKeeper; 86 87 -- 若移動游標后有數據,一直循環讀取 88 WHILE (@@FETCH_STATUS =0) 89 begin 90 -- 班次特殊處理 91 set @shiftStart = @shiftStart / 100 -1; 92 93 -- 對欠品的特殊處理 94 if @reqType = '95' or @reqType = '99' 95 begin 96 set @rQty = @qty; -- 將總的分配數量設置為欠品 97 end 98 99 -- 獲取部品的Cycle策略,若發貨頻率不等於0,則按照時間別(TYPE = 1602)配料 100 declare @moq int=0, @freq int=0, @preDeli int=0;-- 最小包裝單位 101 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; 102 if @preDeli is not null -- 如果沒有設置提前時間,則不考慮 103 begin 104 set @shiftStart -= @preDeli; -- 減掉提前發貨小時 105 end; 106 107 -- 聲明 制品的滿班產量、部品的單機用量 108 declare @cap int=0, @usage int=0; 109 select @usage=PARM1 from JITM where DSRD=0 and TYPE=2202 and MCHC = @rParentItem and ITMC= @rItemNo;-- 獲取部品的單機用量TYPE=2202 110 select @cap=PARM1 from JITM where DSRD=0 and TYPE=2201 and MCHC = @rParentItem;-- 獲取制品的滿班產量TYPE=2201 111 112 declare @capItem int = @rQty;-- 當前部品的應發數量 113 declare @sendTimes int = 1; -- 發貨次數 114 declare @itemSendQty int = @capItem / @sendTimes; -- 當前部品每次發貨XX件 115 116 -- 發貨頻率、滿班產量、單機用量都設置過,才考慮滿班產量 117 if (@cap > 0 and @usage > 0 and @freq > 0) 118 begin 119 set @capItem = @cap * @usage;-- 當前部品的滿班用量 120 set @sendTimes = 8 / @freq; -- 重新設置發貨頻率 121 set @itemSendQty = @capItem / @sendTimes; -- 當前部品每次發貨XX件 122 end 123 else if (@freq > 0) -- 如果只設置了發貨頻率,那就只按照8除以發貨頻率來計算 124 begin 125 set @capItem = @rQty; 126 set @sendTimes = 8 / @freq; -- 重新設置發貨頻率 127 set @itemSendQty = @capItem / @sendTimes; -- 當前部品每次發貨XX件 128 end 129 else -- 否則就按照集約類型,一次發完 130 begin 131 set @sendTimes = 1; -- 重新設置發貨頻率 132 set @itemSendQty = @rQty; -- 一次都發完 133 end 134 135 -- 設置最遲配送時間 136 declare @lastTime int = @shiftStart + (@sendTimes - 1)*@freq; 137 -- 記錄標准配送數量,有可能一次配送量超過標准的兩次、多次 138 declare @standQty int = @itemSendQty; 139 -- 記錄第幾次配送 140 declare @curTime int=0; 141 142 -- 判斷最小包裝數@moq 143 declare @modQty int=0; 144 if (@moq > 0) 145 begin 146 set @modQty = @itemSendQty % @moq; 147 if(@modQty > 0) 148 begin 149 set @itemSendQty = (@itemSendQty / @moq + 1) * @moq; 150 end 151 end 152 153 -- 計算余料,放在第一次配送 154 declare @yuLiao int = 0; 155 set @yuLiao = @rQty - @itemSendQty * @sendTimes; 156 157 -- 該行是否已經讀取過欠品數據 158 declare @yijing int = 0; 159 declare @mpqQty int = @itemSendQty; -- 考慮過最小包裝后的一次配送數 160 161 -- 以下處理配料情況,即Qty > 0 162 while @rQty > 0 163 begin 164 set @id += 1;--結果行號自增 165 set @curTime += 1; 166 set @rQty -= @itemSendQty; 167 168 -- 若是第一次配料,且存在余料,就放在第一次配送 169 if(@yuLiao >0 and @curTime=1) set @rQty -= @yuLiao; 170 171 -- 修正本次要配料數量 172 if @rQty < 0 173 begin 174 set @itemSendQty = @rQty + @itemSendQty; 175 end 176 177 -- 判斷是合並行,還是新建行 178 declare @existId int = 0; 179 select @existId = Id from @result where [WorkOrderNo]=@rWorkOrderNo and [ParentItem]=@rParentItem and [Jon]=@rJon and [ItemNo]=@rItemNo and [CycleTime]=@shiftStart 180 181 if @reqType = '95' or @reqType = '99' 182 begin 183 -- 插入欠品數據 184 --if @existId > 0 185 --begin 186 -- update @result set QtyQp = QtyQp + @itemSendQty where Id=@existId; 187 --end 188 --else 189 if (@existId < 1) 190 begin 191 insert into @result(Id,[WorkOrderNo],[ParentItem],[Jon],[Workshop],[StartDate],[CycleTime],[ItemNo], Qty, [QtyQp], [ExtrNo], [Whs], [Keeper]) 192 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); 193 end 194 end 195 else if (@reqType = '31') 196 begin 197 -- 插入配料信息 198 if @existId > 0 199 begin 200 update @result set Qty = Qty + @itemSendQty where Id=@existId; 201 end 202 else 203 begin 204 insert into @result(Id,[WorkOrderNo],[ParentItem],[Jon],[Workshop],[StartDate],[CycleTime],[ItemNo], Qty, [QtyQp], [ExtrNo], [Whs], [Keeper]) 205 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); 206 end 207 208 -- 如果行剩余數<=0,再次從出庫池獲取欠品數據 209 if(@rQty <= 0) 210 begin 211 declare @temQp decimal = 0;-- 總欠品數 212 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) 213 if(@temQp > 0 and @yijing = 0) 214 begin 215 set @yijing = 1; -- 已經讀取過一次的欠品不再讀取 216 declare @temRqp int = 0; -- 本次操作的欠品數 217 set @temRqp = @mpqQty - @itemSendQty; -- 考慮MPQ后的配送數 - 當前行已配送數 = 當前行仍需欠品數 218 set @temQp -= @temRqp; 219 if(@temQp <= 0) set @temRqp += @temQp; 220 221 -- 若已經到本班次最后一次配送,則全部配送完 222 if(@curTime >= @sendTimes) 223 begin 224 set @temRqp = @temQp; 225 set @temQp = 0; 226 end 227 update @result set QtyQp = @temRqp where Id = @id; -- 更新當前行的欠品數 228 set @shiftStart += (@temRqp + @itemSendQty) / @standQty * @freq; -- 修改下次配送時點 229 230 while(@temQp > 0) -- 持續把欠品數分配完 231 begin 232 set @temRqp = @mpqQty; 233 if(@shiftStart >= @lastTime) -- 若到最后一次配送時點,則把剩余欠品全部計算 234 begin 235 set @shiftStart = @lastTime; 236 set @temRqp = @temQp; 237 set @temQp = 0; 238 end 239 else set @temQp -= @temRqp; 240 if(@temQp <= 0) set @temRqp += @temQp; 241 set @id += 1; 242 243 -- 插入下一個配送時點的欠品數據 244 insert into @result(Id,[WorkOrderNo],[ParentItem],[Jon],[Workshop],[StartDate],[CycleTime],[ItemNo], Qty, [QtyQp], [ExtrNo], [Whs], [Keeper]) 245 values(@Id, @rWorkOrderNo , @rParentItem , @rJon , @rWorkshop , convert(varchar(10),@rWorkStartDate,120), @shiftStart , @rItemNo , 0, @temRqp, @extrNo, @rWhs, @rKeeper); 246 set @shiftStart += @temRqp / @standQty * @freq; -- 更新配送時點 247 end 248 end 249 end 250 end 251 252 -- 發貨時間點增加 253 set @shiftStart += @itemSendQty / @standQty * @freq; 254 if @shiftStart >= 24 255 begin 256 set @shiftStart %= 24; 257 set @rWorkStartDate = DATEADD(DAY, 1, @rWorkStartDate) 258 end 259 end 260 261 -- 獲取下一行 262 fetch next from kitItemRow into @rId, @rWorkOrderNo, @rParentItem, @rJon, @rWorkshop, @rWorkStartDate, @rItemNo, @rQty, @shiftStart, @reqType, @qty , @extrNo, @rWhs, @rKeeper; 263 end 264 265 -- 關閉游標 266 close kitItemRow; 267 -- 釋放游標 268 DEALLOCATE kitItemRow; 269 270 -- 返回結果 271 --SELECT [WorkOrderNo], [ParentItem], [Jon], [Workshop], [StartDate], [CycleTime], [ItemNo], [Qty], [QtyQp], [Keeper], [Whs] from @result 272 --where qty>0 and qtyqp > 0 273 --group by [ParentItem],[Jon],[Workshop],[StartDate],[CycleTime],[ItemNo] 274 --order by [StartDate],[CycleTime], WorkOrderNo, [ItemNo]; 275 RETURN 276 END
