在持久计算列中运行总计

时间:2017-08-16 14:24:05

标签: sql-server tsql sql-server-2012

我在SQL Server 2012中有一个表,如下所示:

import {Container, Content, Text} from 'native-base';

我想添加一个计算的,持久的列,它将为我提供每个客户的运行余额。目前,我使用此查询来获取每个客户的运行余额:

CREATE TABLE [dbo].[CustomerLedgerEntries]
(
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [CustReference] [bigint] NOT NULL,
    [DebitAmount] [decimal](18, 2) NOT NULL,    
    [CreationTime] [datetime] NOT NULL,
    [Description] [nvarchar](512) NULL,
    [ProductId] [nvarchar](32) NULL,

    CONSTRAINT [PK_dbo.CustomerLedgerEntries] 
        PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]

我尝试使用此查询添加计算列:

SELECT 
    Id, CustReference, CreationTime, DebitAmount, CreditAmount, 
    SUM(DebitAmount - CreditAmount) OVER (PARTITION BY CustReference ORDER BY Id 
                                          ROWS UNBOUNDED PRECEDING) AS Balance 
FROM
    CustomerLedgerEntries

但它引发了一个错误:

  

Msg 4108,Level 15,State 1,Line 8
  窗口函数只能出现在SELECT或ORDER BY子句中。

我怎样才能做到这一点?

编辑1: 按照以下@JM_建议并创建UDF后,在表格中,余额显示如下:

ALTER TABLE dbo.CustomerLedgerEntries ADD Balance AS (SUM(DebitAmount - CreditAmount) OVER (PARTITION BY CustReference ORDER BY Id ROWS UNBOUNDED PRECEDING));

然而,当我运行查询Id CusReference CreationTime DebitAmount CreditAmount Balance 30 3 2017-07-12 15:26:36.753 15000.00 0.00 14000.00 31 3 2017-07-12 15:26:36.753 0.00 1000.00 14000.00时,结果显示正确:

Select Id, CustReference, CreationTime, DebitAmount, CreditAmount , Sum(DebitAmount - CreditAmount) Over( Partition By CustReference Order by Id rows Unbounded Preceding) As Balance From CustomerLedgerEntries

所以差不多......但不是那里。请帮忙吗?

2 个答案:

答案 0 :(得分:1)

我假设您的表有一个信用列,但上面的脚本没有包含它。您可以使用UDF执行此操作:

- 编辑:

CREATE FUNCTION [dbo].[UDF_GetBalance] (@CustRef bigint, @ID bigint)
RETURNS decimal(18,2)
AS
BEGIN
  DECLARE @Balance decimal(18,2)
  SELECT @Balance = SUM(DebitAmount - CreditAmount) OVER (PARTITION BY CustReference ORDER BY Id 
                                      ROWS UNBOUNDED PRECEDING) 
FROM
CustomerLedgerEntries WHERE CustReference =@CustRef and ID <= @id


RETURN @Balance
END


ALTER TABLE CustomerLedgerEntries ADD Balance as (dbo.UDF_GetBalance(CustReference, ID))

答案 1 :(得分:1)

在计算列中使用标量udf这是一个糟糕的想法,原因有很多。一个巨大的问题是,即使未引用计算列,对该表的查询也将以串行方式运行。这是一篇很棒的文章,解释了为什么你不想这样做:Another reason why scalar functions in computed columns is a bad idea

SQL Server 2012提供了索引builds/rebuilds in parallel的功能,但是当您以这种方式使用标量udf时,您将失去该功能。您可以使用this article中引用的traceflag自行测试。

标量函数也有许多其他原因。为了获得限制CustomerLedgerEntries表上串行执行的最佳性能,我将使用iTVF(请注意,我无法对此进行测试)。 iTVF允许您使用 所有 您的CPU。

CREATE FUNCTION dbo.UDF_GetBalance (@CustRef bigint)
RETURNS TABLE AS RETURN
  SELECT balance = SUM(DebitAmount - CreditAmount) 
    OVER (PARTITION BY CustReference ORDER BY Id ROWS UNBOUNDED PRECEDING) 
FROM CustomerLedgerEntries 
WHERE CustReference =@CustRef;
GO