从SQL计算列

时间:2017-04-17 18:28:15

标签: sql sql-server stored-procedures calculated-field

首先我很抱歉,如果这是一个重复的问题,但我不知道如何搜索它。这是我的问题。

我有一个从存储过程填充的表。此sp执行大量计算,然后更新表。最后一次计算是长度字段的批量数量和。我运行一个游标(我知道不好主意,但我的老板想要这样)并且在游标中我有第二个游标运行。外部光标从table-1中拉出行(标记#,qty,length),然后将长度与之前的拉长度进行比较,如果它们匹配则将数量加起来。

虽然存储过程运行并且几乎完成了应该执行的操作。问题是如果标记号不是连续的(例1,2,3),它将把总数放在所有具有相同长度的行中。

以下是报告当前的输出方式:

Mark#   |Qty |Length  |Batch Qty
---------------------------------
1214-G30|112 |41.4882 |770
---------------------------------
1214-G33|84  |41.4882 |770
---------------------------------
1214-G38|574 |41.4882 |770
---------------------------------

我需要的是以下输出:

Mark#   |Qty |Length  |Batch Qty
---------------------------------
1214-G30|112 |41.4882 | -
---------------------------------
1214-G33|84  |41.4882 | - 
---------------------------------
1214-G38|574 |41.4882 |770
---------------------------------

以下是完成所有工作的存储过程:

    --Clear CrossBar Report Table
Truncate Table tbl_CrossBarRpt

--Check for open Cursor
If (CURSOR_STATUS('global', 'FACursor'))>=-1
Begin
    If (Select CURSOR_STATUS('global', 'FACursor'))>-1
    Begin
        Close FACursor
    End
    Deallocate FACursor
End


--Dump base data into Cross Bar Report Table
Insert Into tbl_CrossBarRpt(ordernum, materialdesc, marknum)
Select oh.ordernum,gt.material_descFS, od.marknum
From tbl_order_head oh
Join tbl_order_detail od
ON oh.ordernum = od.ordernum
Join tbl_grating_type gt
On oh.gratingnum = gt.grating_type
Where oh.ordernum = @ordernum



--Set variables based on order Number
Declare @bbin as Decimal(18,4); --Bearing Bar Inches
Declare @cbd as Decimal(18,4); --Cross bar Divider
Declare @mtth as Decimal(18,4); --Mount Thickness
Declare @tsp as Decimal(18,4); --Tolerance Support Rod
Declare @tfr as Decimal(18,4); --Tolerance Filling Rod
Declare @totqty as Int; --Total Quantity
Declare @length as Decimal(18,4); --Length
Declare @FA as Decimal(18,4); --Variable FA
Declare @TEM as Decimal(18,4); --Variable TEM
Declare @MEMT as Decimal(18,4); --variable MEMT
--Declare @ReturnValue Decimal(18,4); --Return FA value


--Set Cross Bar Divider
--Exec @cbd = sp_GetCrossbarDivider @ordernum;
Set @cbd = (Select gt.cross_bar_divider
            From tbl_grating_type gt
            Join tbl_order_head oh
            On oh.gratingnum = gt.grating_type
            Where oh.ordernum = @ordernum)

--Set Mounting Thickness
--Exec @mtth = sp_GetMountingThickness @ordernum;
Set @mtth = (Select mt.mnt_thickness
             From tbl_mount mt
             Join tbl_order_head oh
             On oh.banding = mt.mnt_designation
             Where oh.ordernum = @ordernum)

--Set Tolerance Support Rod
--Exec @tsp = sp_GetTolerance @ordernum;
Set @tsp = (Select tl.tol_support_rod
            From tbl_tolerance tl
            Join tbl_order_head oh
            On oh.tolerance = tl.tol_description
            Where oh.ordernum = @ordernum)

--Set Tolerance Filling Rod
Set @tfr = (Select tl.tol_filling_rod
            From tbl_tolerance tl
            Join tbl_order_head oh
            On oh.tolerance = tl.tol_description
            Where oh.ordernum = @ordernum)


--Set Tolerance Support Rod min Mesh
--Exec @MEMT = sp_GetToleranceMesh @ordernum;
Set @MEMT = (Select tl.tol_support_rod_min_mesh
             From tbl_tolerance tl
             Join tbl_order_head oh
             On oh.tolerance = tl.tol_description
             Where oh.ordernum = @ordernum)

--Set up cursor for CrossBar input value
Declare @BearingBar Decimal(18,4);
Declare @CrossBar  Decimal(18,4);
Declare @MarkNum as varchar(25);
Declare @Qty as Int;

Declare FACursor Cursor
For
Select od.bbin, od.cbin, od.marknum, od.qty
From tbl_order_detail od
Where od.ordernum = @ordernum

Open FACursor

Fetch Next From FACursor Into
@BearingBar, @Crossbar, @MarkNum, @Qty

While @@FETCH_STATUS = 0
Begin
    --Calculate FA
    Set @FA = Round((@BearingBar*25.4)/@cbd,0,1)

    Set @TEM = (((@BearingBar * 25.4) - @mtth - @mtth - @tsp) - ((@FA -1) * @cbd))/2

    If (@TEM < @MEMT)
    Begin
        Set @FA = @FA -1
        Set @TEM = (((@BearingBar * 25.4) - @mtth - @mtth - @tsp) - ((@FA -1) * @cbd))/2
        If (@TEM < @MEMT)
        Begin
            Set @FA = @FA -1
            Set @TEM = (((@BearingBar * 25.4) - @mtth - @mtth - @tsp) - ((@FA -1) * @cbd))/2
        End
    End

    If (@TEM < ((@cbd/2) + (@cbd*.05)))
    Begin
        Set @FA = @FA -1
        Set @TEM = (((@BearingBar * 25.4) - @mtth - @mtth - @tsp) - ((@FA -1) * @cbd))/2
    End

    --Calculate Total Qty
    Set @totqty = @Qty * @FA

    --Insert Total Qty value into table Cross Bar Report
    Update tbl_CrossBarRpt Set totqty = @totqty Where marknum = @MarkNum

    --Calculate Length Value
    Set @length = ((@CrossBar *25.4)-@tfr)/25.4

    --Insert Length value into table Cross Bar Report
    Update tbl_CrossBarRpt Set length = @length Where marknum = @MarkNum

    --Get next row of data
    Fetch Next From FACursor Into
    @BearingBar, @Crossbar, @MarkNum, @Qty
End

--Close Cursor
If (CURSOR_STATUS('global', 'FACursor'))>=-1
Begin
    If (Select CURSOR_STATUS('global', 'FACursor'))>-1
    Begin
        Close FACursor
    End
    Deallocate FACursor
End

--Create Temp table for Batch Qty Processing
Select cbr.marknum, cbr.totqty, cbr.length
into #tbl_BQProcess
From tbl_CrossBarRpt cbr
Order By cbr.length Desc, cbr.marknum

--Set up variables for Batch Qty Processing Cursor
Declare @bMarknum as varchar(25);
Declare @bTotQty as int = 0;
Declare @bLeng as decimal(18,4) = 0.0000;
Declare @bLength1 as decimal (18,4) = 0.0000;
Declare @bLength2 as Decimal(18,4) = 0.0000;
Declare @bQty as int = 0;
Declare @bPrevLeng as decimal(18,4) = 0.0000;

Declare BQOutterCursor Cursor
For
Select cr.marknum, cr.totqty, cr.length
From tbl_CrossBarRpt cr
Where cr.ordernum = @ordernum

Open BQOutterCursor

Fetch Next From BQOutterCursor Into
@bMarkNum, @bTotQty, @bLeng

While @@FETCH_STATUS = 0
Begin
    If @bPrevLeng = @bLeng
        Begin
            Goto Cont
        End
    Else
    Begin
        Declare @ibMarknum as varchar(25);
        Declare @ibTotQty as int = 0;
        Declare @ibLeng as decimal(18,4) = 0.0000;
        Declare @ibLength1 as decimal (18,4) = 0.0000;
        Declare @ibLength2 as Decimal(18,4) = 0.0000;
        Declare @ibQty as int = 0;

        Declare BQInnerCursor Cursor
        For
        Select bqp.marknum, bqp.totqty, bqp.length
        From #tbl_BQProcess bqp
        Order by bqp.length Desc, bqp.marknum

        Open BQInnerCursor

            Fetch Next From BQInnerCursor Into
            @ibMarkNum, @ibTotQty, @ibLeng

        While @@FETCH_STATUS = 0
        Begin
            If @ibLeng = @bLeng
            Begin
                Set @ibQty = @ibQty + @ibTotQty
            End

            Fetch Next From BQInnerCursor Into
            @ibMarkNum, @ibTotQty, @ibLeng
        End
    End

    --Update batch Qty totals
    Update tbl_CrossBarRpt
    Set batchqty = @ibQty
    Where marknum = @bMarknum

    --Close Inner Cursor
    If (CURSOR_STATUS('global', 'BQInnerCursor'))>=-1
    Begin
        If (Select CURSOR_STATUS('global', 'BQInnerCursor'))>-1
        Begin
            Close BQInnerCursor
        End
        Deallocate BQInnerCursor
    End


    Cont:

        --Update Prev Length to current length
        Set @bPrevLeng = @bLeng

        Fetch Next From BQOutterCursor Into
        @bMarkNum, @bTotQty, @bLeng



    End

    --Close Outter Cursor
    If (CURSOR_STATUS('global', 'BQOutterCursor'))>=-1
    Begin
        If (Select CURSOR_STATUS('global', 'BQOutterCursor'))>-1
        Begin
            Close BQOutterCursor
        End
        Deallocate BQOutterCursor
    End

    --Drop temp table
    Drop Table #tbl_BQProcess

有没有人对如何保留重复内容有任何想法。

提前致谢。

1 个答案:

答案 0 :(得分:2)

我不确定为什么坚持使用游标,但我认为你的整个外部和内部游标都可以被替换为:

select cbr.marknum, 
cbr.length,
case when row_number() over(partition by cbr.length order by cbr.length desc, cbr.marknum desc) = 1 
then sum(cbr.totqty) over (partition by cbr.length order by cbr.length, cbr.marknum) else null end batchqty
from tbl_CrossBarRpt cbr
order by length, marknum

如果您需要使用batchqty实际更新tbl_CrossBarRpt而不是仅选择值,则可以这样做:

update tbl_CrossBarRpt
set batchqty = x.batchqty
from tbl_CrossBarRpt t
join (select cbr.marknum, 
      case when row_number() over(partition by cbr.length order by cbr.length desc, cbr.marknum desc) = 1 
      then sum(cbr.totqty) over (partition by cbr.length order by cbr.length, cbr.marknum) else null end batchqty
      from tbl_CrossBarRpt cbr) x on x.marknum = t.marknum