How do I Specify Computed Columns in a Table which are based on another Column in SQL Server?

99 Views Asked by At

I have the following fabricated data seen below.

I would like to alter the Total_Investment Column to make it a Computed Column which computes the total Dollar_Amount for the Unit Name that is present in that row.

For example, for Row 1, the Total_Investment slot would show the sum of both rows that are listed as 'Healthy_Communities', so rows 1 and 6, eg., 5899.00 + 1766.00.

Row 2 would sum all three (2, 5, and 9) of the Urban entries, and so on. How do I accomplish this in SQL Sever 2012?

Project_ID  Unit_Name             Fiscal_Year  Dollar_Amount  Total_Investment
1           Healthy Communities   2000-01-01   5899.00        0.00
2           Urban                 2009-01-01   6008.00        0.00
3           Rivers and Watersheds 2006-01-01   6835.00        0.00
4           Large Landscapes      2011-01-01   5216.00        0.00
5           Urban                 2015-01-01   3555.00        0.00
6           Healthy Communities   2014-01-01   1766.00        0.00
7           Youth Engagement      2004-01-01   4246.00        0.00
8           Rivers and Watersheds 2014-01-01   8253.00        0.00
9           Urban                 2000-01-01   5590.00        0.00
10          Outdoor Recreation    2013-01-01   5356.00        0.00

I'm aware of the alter table documentation for computing columns but don't know how to modify this code to fit my problem.

2

There are 2 best solutions below

0
On BEST ANSWER

Only replace MyTable below with the name of your table. The drawback of this method is that it becomes really expensive if working with many rows (e.g. 40 s for 10000). For such a case, you can use a view. (Thanks to @Amit for insisting on the UDF. Sorry, the performance is aweful)

Edit: Added nonclustered index on Unit_Name, including Dollar_Amount. Performance improved tenfold.

-- drop table MyTable;
-- drop function udfMyTable;

-- go

create table MyTable(
 project_id int identity(1, 1) primary key,
 Unit_Name varchar(120),
 Dollar_Amount decimal(19, 2),
)

go
create nonclustered index IX_Unit on dbo.MyTable(Unit_Name) include (Dollar_Amount);

create function udfMyTable (@pk as int)
returns decimal(19, 2)
as
begin
declare @res as decimal(19, 2);
select 
    @res=sum(Dollar_Amount) 
from 
    MyTable 
where Unit_Name in (select Unit_Name from MyTable where project_id=@pk);
return @res;
end
go
alter table MyTable add Total_Amount as dbo.udfMyTable(project_id)
go


insert into MyTable (unit_name, dollar_amount) values
('Healthy Communities',   '5899.00'),
('Urban',                 6008.00),
('Rivers and Watersheds', 6835.00),
('Large Landscapes',      5216.00),
('Urban',                 3555.00),
('Healthy Communities',   1766.00),
('Youth Engagement',      4246.00),
('Rivers and Watersheds', 8253.00),
('Urban',               5590.00),
('Outdoor Recreation', 5356.00)

select * from MyTable;
0
On

Yes you would create a user-defined function to do the calculation and use that user-defined function in the expression of Computed column.

A working example would be something like.....

CREATE TABLE TABLE1 (ID INT, VALUE INT)
GO
INSERT INTO TABLE1 VALUES (1 , 10), (2 , 20) , (3 , 30)
GO

CREATE FUNCTION dbo.udf_DefaultValue(@ID INT)
RETURNS INT
AS
BEGIN
    DECLARE @rtnValue INT;
    SELECT @rtnValue = VALUE *2 FROM TABLE1 WHERE ID = @ID
    RETURN @rtnValue;
END
GO

CREATE TABLE TABLE2 (ID INT
                  , VALUE INT
                  , ComputedColumn AS (VALUE * dbo.udf_DefaultValue(ID)) )
GO

INSERT INTO TABLE2 (ID , VALUE)
VALUES (1, 1)

SELECT * FROM TABLE2

/*****  Result Set  *****/

ID  VALUE   ComputedColumn
1     1           20