2017-08-16 65 views
0

运行总计我有一个表在SQL Server 2012中是这样的:在持久化计算列

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 

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

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

但它抛出一个错误:

Msg 4108, Level 15, State 1, Line 8
Windowed functions can only appear in the SELECT or ORDER BY clauses.

我该如何做到这一点?

编辑1: 低于以下@JM_建议,并创建一个UDF后,在表中的余额显示如下:

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结果显示正确:

30 3 2017-07-12 15:26:36.753 15000.00 0.00 15000.00 31 3 2017-07-12 15:26:36.753 0.00 1000.00 14000.00

所以几乎没有......但也不能令人信服。请问有什么帮助吗?

+3

你正在尝试做的是不支持的,因为计算列具有信息只有大约是inserted..you可以创建尽管 – TheGameiswar

+1

它不支持,因为它不确定性的视图的行。由于可以使用较早的ID添加新记录,从而导致该ID之后的所有记录重新评估给定的custReference;引擎无法更新超过这一条记录。计算列中不可能做什么。 – xQbert

+0

在计算中如何使用UDF? –

回答

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 [email protected] and ID <= @id 


RETURN @Balance 
END 


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

请参阅我的**编辑1 **以上,如果有什么方法可以帮忙? – Sleek

+0

将其更改为使用ID将其保留为仅当前记录并低于 –

+0

太棒了! Works @JM_。谢谢你! – Sleek

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 [email protected]; 
GO 
+0

我创建了这个iTVF,但我不知道如何使用它。我如何? – Sleek