计算运行总计

时间:2014-01-15 21:17:53

标签: tsql sql-server-2008-r2

我正在尝试为特定的EmployeeID重新计算几个不同的数据列。

我希望hrs_YTD列保持运行总计。更新此信息的好方法是什么?

HRS_YTD目前有0.00值。我不想在下表中得到结果。

ID | CHEKDATE | CHEKNUMBR | HRS | HRS_YTD

EN344944 | 01/1/2014 | dd1001 | 40.00 | 40.00

EN344944 | 2014年1月8日| dd1002 | 30.00 | 70.00

EN344944 | 1/15/2014 | dd1003 | 32.50 | 102.50

等.....

DECLARE @k_external_id varchar(32)

SET @k_external_id = 'EN344944'

SELECT * INTO #tmpA
FROM dbo.gp_check_hdr a
WHERE a.EMPLOYID = @k_external_id

SELECT a.ID, a.CHEKNMBR, a.CHEKDATE,
       (SELECT CAST(SUM(a.[hours]) as decimal(18,2)) FROM #tmpA b 
        WHERE (b.CHEKDATE <= a.CHEKDATE and YEAR(b.CHEKDATE) = 2013)) AS hrs_ytd
FROM #tmpA a
WHERE YEAR(a.CHEKDATE) = 2013

我真的不知道我是否可以像使用#tmpA b那样使用别名,但过去它对我有用。这并不意味着它是一种很好的做事方式。有人能告诉我一种方法来实现我需要的结果吗?

3 个答案:

答案 0 :(得分:3)

没有对此进行测试,但您可以尝试一下

DECLARE @k_external_id varchar(32)

SET @k_external_id = 'EN344944'

SELECT g1.primarykey, g1.ID,g1.CHEKDATE, g1.CHEKNUMBR, g1.HRS ,(SELECT SUM(g2.HRS)
                   FROM dbo.gp_check_hdr g2
                   WHERE g2.ID = @k_external_id AND
                  (g2.primarykey <= g1.primarykey)) as HRS_YTD
FROM   dbo.gp_check_hdr g1
WHERE g1.ID = @k_external_id
ORDER BY g1.primarykey;

http://www.codeproject.com/Articles/300785/Calculating-simple-running-totals-in-SQL-Server

答案 1 :(得分:1)

我这样做的方式是computed columnuser defined function的组合。

该功能允许聚合数据。在计算列中,您只能使用同一行的字段,因此调用函数(允许)是必要的。

计算列允许它连续工作,无需任何其他查询或临时表等。一旦设置,您不需要运行夜间更新或触发器或任何类型的东西来保持数据更新,包括记录何时更改或删除。

这是我的解决方案......和SqlFiddle:http://www.sqlfiddle.com/#!3/cd8d6/1/0

修改 我已对此进行了更新,以反映您需要计算每位员工的运行总计。 SqlFiddle也更新了。

功能:

Create Function udf_GetRunningTotals ( 
    @CheckDate DateTime,
    @EmployeeID int 
)
Returns Decimal(18,2)
As
Begin
    Declare @Result Decimal(18,2)
    Select @Result = Cast(Sum(rt.Hrs) As Decimal(18,2))
        From RunningTotals rt 
        Where rt.CheckDate <= @CheckDate 
            And Year(rt.CheckDate) = Year(@CheckDate)
            And rt.EmployeeID = @EmployeeID
    Return @Result
End

表架构:

Create Table [dbo].[RunningTotals](
    [ID] [int] Identity(1,1) NOT NULL,
    [EmployeeID] [int] NOT NULL,
    [CheckDate] [datetime] NOT NULL,
    [CheckNumber] [int] NOT NULL,
    [Hrs] [decimal](18, 2) NOT NULL,
    [Hrs_Ytd]  AS ([dbo].[udf_GetRunningTotals]([CheckDate],[EmployeeID])), -- must add after table creation and function creation due to inter-referencing of table and function

    Constraint [PK_RunningTotals3] Primary Key Clustered (
        [ID] ASC
    ) With (
        PAD_INDEX = OFF, 
        STATISTICS_NORECOMPUTE = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS = ON
    ) 
) On [PRIMARY]

结果将计算每年的年初至今。

注意 -

您不能按原样创建函数或表,因为它们相互引用。 首先,使用除计算列之外的所有列创建表; 然后,创建该功能。 最后,更改表并添加计算列。

这是一个完整运行的测试脚本:

-- Table schema
Create Table [dbo].[RunningTotals](
    [ID] [int] Identity(1,1) NOT NULL,
    [EmployeeID] [int] NOT NULL,
    [CheckDate] [datetime] NOT NULL,
    [CheckNumber] [int] NOT NULL,
    [Hrs] [decimal](18, 2) NOT NULL,

    Constraint [PK_RunningTotals3] Primary Key Clustered (
        [ID] ASC
    ) With (
        PAD_INDEX = OFF, 
        STATISTICS_NORECOMPUTE = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS = ON
    ) 
) On [PRIMARY]
Go

-- UDF Function to compute totals
Create Function udf_GetRunningTotals ( 
    @CheckDate DateTime,
    @EmployeeID int 
)
Returns Decimal(18,2)
As
Begin
    Declare @Result Decimal(18,2)
    Select @Result = Cast(Sum(rt.Hrs) As Decimal(18,2))
        From RunningTotals rt 
        Where rt.CheckDate <= @CheckDate 
            And Year(rt.CheckDate) = Year(@CheckDate)
            And rt.EmployeeID = @EmployeeID
    Return @Result
End
Go

-- Add the computed column to the table
Alter Table RunningTotals Add [Hrs_Ytd] As (dbo.udf_GetRunningTotals(CheckDate, EmployeeID))
Go

-- Insert some test data
Insert into RunningTotals Values (334944, '1/1/2014', '1001', 40.00)
Insert into RunningTotals Values (334944, '1/5/2014', '1002', 30.00)
Insert into RunningTotals Values (334944, '1/15/2014', '1003', 32.50)

Insert into RunningTotals Values (334945, '1/5/2014', '1001', 10.00)
Insert into RunningTotals Values (334945, '1/6/2014', '1002', 20.00)
Insert into RunningTotals Values (334945, '1/8/2014', '1003', 12.50)


-- Test the computed column
Select * From RunningTotals

答案 2 :(得分:0)

你的子查询应该可以正常工作。

我使用表变量代替临时表。

我还将临时表中插入的结果限制为2013,以简化最终的select语句,并将临时表中的结果限制为您所需的结果。唯一的另一件事是使用ID将子查询加入主查询,但是你应该工作,因为你将临时表中的结果限制为特定的ID。

DECLARE 
     @k_external_id varchar(32)
    ,@k_reporting_year int

SET @k_external_id = 'EN344944'
SET @k_reporting_year = 2013

DECLARE @temp TABLE(
     ID NVARCHAR(32)
    ,CheckDate DATE
    ,CheckNumber NVARCHAR(6)
    ,HRS DECIMAL(18,2)
)

INSERT INTO @temp (
     ID
    ,CheckDate
    ,CheckNumber
    ,HRS
)
    SELECT
         ID
        ,CHEKDATE
        ,CHEKNMBR
        ,[hours]
    FROM
        dbo.gp_check_hdr
    WHERE 
            EMPLOYID = @k_external_id
        AND YEAR(a.CHEKDATE) = @k_reporting_year

SELECT 
     ID
    ,CheckDate
    ,CheckNumber
    ,HRS
    ,(SELECT SUM(HRS) FROM @temp b WHERE a.ID = b.ID AND b.CheckDate <= a.CheckDate) AS hrs_ytd
FROM
    @temp a