MS SQL Computed column - sql

I want to create a column based on COUNT(*) on another table, and when a record is deleted from that table it should decrease the value in this new column and vice versa. So, here is the query:
SELECT COUNT (*) FROM dbo.Korisnik1_FakturaStavka GROUP BY dbo.Korisnik1_FakturaStavka.FakturaID
And it returns this:
And when I try to create a computated column like this:
CREATE TABLE test(
NumberOF as (SELECT COUNT (*) FROM dbo.Korisnik1_FakturaStavka GROUP BY dbo.Korisnik1_FakturaStavka.FakturaID) )
I get the following error:
Subqueries are not allowed in this context. Only scalar expressions are allowed.
Here is the main table that I want to compute from:
How can I resolve this ?

You can define a UDF:
create function dbo.NumberOfFakturaID(#id int) returns int as begin
return (select count(1) from Korisnik1_FakturaStavka where id=#id)
end
and then use it as the computed column:
CREATE TABLE test(FakturaID int, NumberOF as dbo.NumberOfFakturaID(FakturaID))
But putting that sort of calc as a computed column should be used with care.

This is too long for a comment.
You can do this by defining a function to calculate the count and using that function in the computed column definition. However, I don't think this is a good idea for frequently used columns, because you will be doing a lot of counting "behind the scenes".
Alternatives:
Set up a view or materialized view with the additional count column.
Do the count explicitly when you need it.
Set up a trigger to store the count in the first table, whenever rows are inserted/updated/deleted from the second table.

Related

unique constraint on window function output

I want to create lists of items and prevent the entry of 2 identical lists, using a unique constraint on a computed column.
CREATE TABLE test_cc
(
list_id int,
list_item int,
list_items AS STRING_AGG(CONVERT(varchar(10), list_item),',') OVER (PARTITION BY list_id) WITHIN GROUP (ORDER BY list_item),
UNIQUE(bs)
);
INSERT INTO test_cc VALUES (1, 1),(1,2),(2,1),(2,2);
/*should not be possible.*/
Executing this on SQL Server 2019 returns Error Msg 4113 Level 16 during table creation.
Is declaring a unique constraint on an expression a good practice ?
My data volume for this table is not huge.
Making sure that lists are unique are difficult. As I mentioned in the comments you can't use aggregate function in a computed column; a computed column is a value calculated based on the row, not the table.
You also can't use an Indexed View with a UNIQUE INDEX on a STRING_AGG'd column, as STRING_AGG isn't allowed to be used in an indexed view.
One method, therefore, is to use a TRIGGER, however, this won't be performant; in fact as your table grows this is going to get increasingly slower. For a small dataset it should be fine.
CREATE TRIGGER dbo.UnqTrg_list_items_test_cc ON dbo.test_cc
AFTER INSERT,UPDATE,DELETE AS
BEGIN
IF EXISTS (SELECT 1
FROM (SELECT STRING_AGG(cc.list_item,',') WITHIN GROUP (ORDER BY cc.list_item) AS list_items
FROM dbo.test_cc cc
GROUP BY cc.list_id) SA
GROUP BY list_items
HAVING COUNT(list_items) > 1)
THROW 96432, N'Violation of Unique Trigger logic ''UnqTrg_list_items_test_cc''. Cannot insert duplicate list in object ''dbo.test_cc''. The statement has been aborted.',10;
END;
db<>fiddle demonstrating INSERT,DELETE and UPDATE failing.

SQL function in column

I have a table in my SQL database. It has already some data and I have to add a new column. The value of the column should be created by a SQL function I'd definded. The parameters are two values from the table.
When I SELECT the data it's to late to call the function.
So I have value1 and value2 in my table. And I have a third column which should calculated like this function(value1, value2).
I only found solutions which execute the function at the SELECT.
Can anyone help me how to do this?
Use a computed column:
alter t add function_column as (function(value1, value2));
This will be calculated when it is accessed -- which means every time you use it. If you want the value calculated only once, then you would need to add a new column and a trigger to keep it up-to-date.

Common methods for doing select with computation by need?

I would like to be able to add columns to a table with cells who's values are computed by need at 'querytime' when (possibly) selecting over them.
Are there some established ways of doing this?
EDIT: Okay I can do without the 'add columns'. What I want is to make a select query which searches some (if they exist) rows with all needed values computed (some function) and also fills in some of the rows which does not have all needed values computed. So each query would do it's part in extending the data a bit.
(Some columns would start out as null values or similar)
I guess I'll do the extending part first and the query after
You use select expression, especially if you don't plan to store the calculation results, or they are dependant on more than one table. An example, as simple as it could be:
SELECT id, (id+1) as next_id FROM table;
What type of database are you asking for? If it is SQL Server then you can use the computed columns by using the AS syntax.
Eg:
create table Test
(
Id int identity(1,1),
col1 varchar(2) default 'NO',
col2 as col1 + ' - Why?'
)
go
insert into Test
default values
go
select * from Test
drop table Test
In the SQL world it's usually expensive to add a column to an existing table so I'd advise against it. Maybe you can manage with something like this:
SELECT OrderID,
ProductID,
UnitPrice*Quantity AS "Regular Price",
UnitPrice*Quantity-UnitPrice*Quantity*Discount AS "Price After Discount"
FROM order_details;
If you really insist on adding a new column, you could go for something like (not tested):
ALTER TABLE order_details ADD column_name datatype
UPDATE order_details SET column_name = UnitPrice+1
You basically ALTER TABLE to add the new column, then perform an UPDATE operation on all the table to set the value of the newly added column.

How to add a column to select statement inside CTE to add value later

I want to add a dummy column in CTE.
Later I want to update the value of dummy column using update statement.
I am getting Update or Insert of view or function failed because it contains a derived or constant field.
The CTE is
with CTE
AS
(
Select A.a, cast(NULL as varchar(20)) as F // cast expression is failed attempt to add dummy column.
FROM ABC A
)
I am getting exception after updating F field using update statement.
A CTE is basically a convenience to avoid having to use either
a) the same inline sql multiple times or
b) a temporary table
If you want to add a column to this set, you can do it by joining your CTE to whatever it is you want to add.

Dynamic field in SQL Server Express

So I've found myself with a need to have a field in my table that is a count of all the 'Shops' in another table. The table should therefore consist of Centre_Name, Location and Shop_Count. I've already created the table, so how do I add such a field?
The field should also obviously update when a shop is added or deleted in the other table. Also, each shop has a corresponding Centre_Name.
The table is in a SQL Server Express database, linked to my MVC 4 project in Visual Studio.
Thanks!
It's pretty heavy denormalization, but you could make a function to get the count and then use that function as part of a computed column. See: define a computed column reference another table
So you'd want to do:
CREATE FUNCTION dbo.CountShops (#Centre_Name VARCHAR[x])
RETURNS INT
AS BEGIN
DECLARE #ShopCount INT
SELECT #ShopCount = COUNT(*) FROM dbo.Shops WHERE Centre_Name = #Centre_Name
RETURN #ShopCount
END
And then call that as part of your column:
ALTER TABLE dbo.Shops
ADD Shop_Count AS dbo.CountShops(Centre_Name)
...this is assuming Centre_Name is the defining attribute of what you're counting shops by. What are you counting shops by? If it's just counting rows in the shops table, you could drop the parameter and do:
CREATE FUNCTION dbo.CountShops ()
RETURNS INT
AS BEGIN
DECLARE #ShopCount INT
SELECT #ShopCount = COUNT(*) FROM dbo.Shops
RETURN #ShopCount
END
More on computed columns here.