how to calculate column to other table - sql-server

i want to make column Customers_Balance on TBL_CUSTOMERS to show by defult the result of that stored procedures....
TBL_CUSTOMERS which it have the info of the customer, and it created as like that
CREATE TABLE TBL_CUSTOMERS
(
Customers_ID int PRIMARY KEY,
Customers_Name varchar(100) NOT NULL,
Customers_Phone varchar(100),
Customers_Address varchar(100),
Customers_Web varchar(100),
Customers_Balance decimal(16,0) not null,
);
TBL_CUSTOMERS_DETAILS which it have the details of all customer transactions , and it created as like that
CREATE TABLE TBL_CUSTOMERS_DETAILS
(
Customers_Details_ID int PRIMARY KEY,
Customers_ID int,
Customers_Details_Tybe varchar(50) not null,
Customers_Details_Date date not null,
Customers_Details_Amount decimal(16,0) not null,
);
i have created stored procedures to calculate the result of sum of customer's transactions balance and worked fine, and it created as like that
CREATE PROC SP_SUM_CUSTOMERS_DETAILS_AMOUNT
#ID INT
AS
SELECT SUM(Customers_Details_Amount)
FROM TBL_CUSTOMERS_DETAILS
Where Customers_ID = #ID
NOW
i want to make column Customers_Balance on TBL_CUSTOMERS to show by defult the result of that stored procedures....
how i can make something like that ??

Materializing values that can be calculated by other materialize values is usually a bad idea as it bears the risk of inconsistencies.
So you best drop the column Customers_Balance in TBL_CUSTOMERS and the procedure and then create a view which includes the customer's data and their balance. You can do so by a join and aggregation.
ALTER TABLE TBL_CUSTOMERS
DROP COLUMN Customers_Balance;
DROP PROCEDURE SP_SUM_CUSTOMERS_DETAILS_AMOUNT;
CREATE VIEW VW_CUSTOMERS
AS
SELECT C.Customers_ID,
C.Customers_Name,
C.Customers_Phone,
C.Customers_Address,
C.Customers_Web,
sum(CD.Customers_Details_Amount) Customers_Balance
FROM TBL_CUSTOMERS C
INNER JOIN TBL_CUSTOMERS_DETAILS CD
ON CD.Customers_ID = C.Customers_ID
GROUP BY C.Customers_ID,
C.Customers_Name,
C.Customers_Phone,
C.Customers_Address,
C.Customers_Web;

You are looking for a Computed Column
What you need to do is to create a scalar function rather than a stored procedure (simply change your current stored procedure into a scalar function), and then use this function in your computed column. This would give you an auto-updated results on your computed column.
So, redoing your work should be something like this :
-- CREATE THE SCALAR FUNCTION FIRST
CREATE FUNCTION SUM_CUSTOMERS_DETAILS_AMOUNT (#ID INT)
RETURNS INT
AS
BEGIN
RETURN (
SELECT SUM(Customers_Details_Amount)
FROM TBL_CUSTOMERS_DETAILS
WHERE Customers_ID = #ID
)
END
GO
-- NOW DROP THE CURRENT Customers_Balance COLUMN
ALTER TABLE TBL_CUSTOMERS
DROP COLUMN Customers_Balance
GO
-- CREATE THE COMPUTED COLUMN WITH THE FUNCTION
ALTER TABLE TBL_CUSTOMERS
ADD Customers_Balance AS dbo.SUM_CUSTOMERS_DETAILS_AMOUNT (Customers_ID)
GO

Related

Stored Procedure: Unable to execute after creation

I have created a stored procedure which does four things:
create a table
Alter the created table with a new column
Update the new column based on a condition
Alter table again to drop a column.
I created the stored procedure but cannot execute. I get this error
Column name or number of supplied values does not match table definition'
I have checked all the columns and their datatype to ensure they match so I am at my wit's end as to where it has gone wrong. This is my first time writing a stored procedure, so it may be that my code structure is completely wrong. I have attached a simplified code here showing the basic structure and I am hoping if someone can have a look if the structure is right and shed some light!
Thanks a lot
Michelle
SET ANSI_NULLS ON
GO
CREATE PROCEDURE myStoredProcedure
AS
BEGIN
SET NOCOUNT ON
IF OBJECT_ID('newTable') IS NULL
BEGIN
CREATE TABLE newTable
(
[name] [nvarchar] (256) NOT NULL,
[id] [int] NOT NULL,
[date] [datetime2] (7) NULL
)
END;
TRUNCATE TABLE newTable;
INSERT INTO newTable
SELECT [name], [id], [date]
FROM table1;
ALTER TABLE newTable
ADD [Flag] [nvarchar](2) NULL;
UPDATE newTable
SET [Flag] = 1
WHERE YEAR([date]) = 2020;
ALTER TABLE newTable
DROP COLUMN [date];
END;
As per the Guru's comments above, rather create the table as it should be created originally, then update data in it accordingly with your SP.
I altered your SP to work, however, this is still not the correct way to actually use a SP.
See below altered SP:
SET ANSI_NULLS ON
GO
CREATE PROCEDURE myStoredProcedure
AS
BEGIN
SET NOCOUNT ON
IF OBJECT_ID('newTable') IS NULL
BEGIN
CREATE TABLE newTable
(
[id] int primary key identity,
[name] nvarchar(256) NOT NULL,
[date] datetime2 (7) NULL ,
[Flag] nvarchar(2) NULL
)
END;
INSERT INTO newTable (
[name],
[date]
)
SELECT
[name],
[date]
FROM table1;
UPDATE newTable
SET [Flag] = 1
WHERE YEAR([date]) = 2020;
END;
I removed the code to drop the Date Column as this is ill advised.

How to assign a permanent unique ID with T-SQL

Can someone let me know how to permanently assign a unique ID to a field?
I have the following table:
CREATE TABLE PrestigeCars.Reference.Staff
(
StaffName NVARCHAR(50) NULL,
ManagerID INT NULL,
Department NVARCHAR(50) NULL
) ON [PRIMARY]
GO
The following code assigns a new id field to to the table called 'myuniqueID'
SELECT
Staff.StaffName
,Staff.ManagerID
,Staff.Department
,NEWID() AS myuniqueID
FROM Reference.Staff
This will produce the following table:
The problem is I would like the unique IDs generated to become permanent.
Can someone let me know if that is possible?
CREATE TABLE PrestigeCars.Reference.Staff (
StaffName NVARCHAR(50) NULL
,ManagerID INT NULL
,Department NVARCHAR(50) NULL
, UniqueId NVARCHAR(255) NOT NULL default NEWID()
) ON [PRIMARY]
GO
Important is, that this only works for creating the table. If you want to alter the table, you firstly have to add the Column which has to allow null, then fill the values and at last set it to not null.
Edit:
To add a Column you need the alter table statement, as mentioned in many other posts before:
ALTER TABLE PrestigeCars.Reference.Staff
ADD UniqueId NVARCHAR(255) NULL default NEWID()
Next you have to set the UniqueId for the existing rows:
UPDATE PrestigeCars.Reference.Staff
SET UniqueId = NEWID()
WHERE UniqueId IS NULL
Last but not least you should set the column to not null:
ALTER TABLE PrestigeCars.Reference.Staff
ALTER COLUMN UniqueId NOT NULL
You could add an Unique-Index, if you want to, but this should not be necessary.

Run A Procedure or a Function on Every New Insert

Is there a way so that in a CREATE TABLE table ( ... ) I can force a procedure or a function to run on every insert?
-- For exmaple:
CREATE TABLE table (
ID INT IDENTITY (1,1) PRIMARY KEY,
Pass varchar(200) -- Can I do Proc(Pass) to return the output instead?
)
You can run a trigger on every new insert and do what you want..You have access to virtual table called inserted inside trigger which contains inserted values
Create trigger name
on tbl
after insert
as
begin
---select * from inserted
--your proc here
end
You might also take a look at computed columns. They are virtual columns in a table computed by an expression defined when the table is created. E.g.:
CREATE TABLE products
(id INT,
price MONEY,
tax AS price * .15);
-- the column tax is computed as 15% of the price whenever a price is changed (inserts or updates). Though having limitations they come in handy in simple cases.

Auto increment a bigint column?

I want a bigint ID column for every row of data that i insert into a table. I want Sql server to generate the numbers. I tried to create a table with a bigint column ID. I want this to be autoincrement with the first value as 1. I tried using [ID] [bigint] AUTO_INCREMENT NOT NULL, in my create table statement, but I got the error - Incorrect syntax near 'AUTO_INCREMENT'. How do I do this ?
Can you not just declare it as an IDENTITY column:
[ID] [bigint] IDENTITY(1,1) NOT NULL;
The 1,1 refers to the start index and the amount it is being incremented by.
NOTE: You do not have to provide a value for the ID column when you do an insert. It will automatically choose it. You can modify these values later if required.
EDIT:
Alternatively, you can use a stored procedure to handle all the inserts.
Example:
Stored Procedure will take in variables as you would a normal insert (one variable for every column). The logic within the stored procedure can select the max value currently existing in the table and choose that as its max value.
DECLARE #yourVariable = SELECT MAX(ID) FROM YourTable
Use #yourVariable as your insert value. You can increment it or change value as necessary.
I got the answer here - http://www.sqlservercentral.com/Forums/Topic1512425-149-1.aspx
CREATE TABLE Test (
ID BIGINT IDENTITY NOT NULL,
SomeOtherColumn char(1)
)
INSERT INTO Test (SomeOtherColumn)
values ('a')

Is it possible to associate Unique constraint with a Check constraint?

I have a table access whose schema is as below:
create table access (
access_id int primary key identity,
access_name varchar(50) not null,
access_time datetime2 not null default (getdate()),
access_type varchar(20) check (access_type in ('OUTER_PARTY','INNER_PARTY')),
access_message varchar(100) not null,
)
Access types allowed are only OUTER_PARTY and INNER_PARTY.
What I am trying to achieve is that the INNER_PARTY entry should be only once per day per login (user), but the OUTER_PARTY can be recorded any number of times. So I was wondering if its possible to do it directly or if there is an idiom to create this kind of restriction.
I have checked this question: Combining the UNIQUE and CHECK constraints, but was not able to apply it to my situation as it was aiming for a different thing.
A filtered unique index can be added to the table. This index can be based on a computed column which removes the time component from the access_time column.
create table access (
access_id int primary key identity,
access_name varchar(50) not null,
access_time datetime2 not null default (SYSDATETIME()),
access_type varchar(20) check (access_type in ('OUTER_PARTY','INNER_PARTY')),
access_message varchar(100) not null,
access_date as CAST(access_time as date)
)
go
create unique index IX_access_singleinnerperday on access (access_date,access_name) where access_type='INNER_PARTY'
go
Seems to work:
--these inserts are fine
insert into access (access_name,access_type,access_message)
select 'abc','inner_party','hello' union all
select 'def','outer_party','world'
go
--as are these
insert into access (access_name,access_type,access_message)
select 'abc','outer_party','hello' union all
select 'def','outer_party','world'
go
--but this one fails
insert into access (access_name,access_type,access_message)
select 'abc','inner_party','hello' union all
select 'def','inner_party','world'
go
unfortunately you cant add a "if" on a check constraint. I advise using a trigger:
create trigger myTrigger
on access
instead of insert
as
begin
declare #access_name varchar(50)
declare #access_type varchar(20)
declare #access_time datetime2
select #access_name = access_name, #access_type= access_type, #access_time=access_time from inserted
if exists (select 1 from access where access_name=#access_name and access_type=#access_type and access_time=#access_time) begin
--raise excetion
end else begin
--insert
end
end
you will have to format the #access_time to consider only the date part

Resources