How to populate a column's value based on two other column's values - sql

I have a table like this:
| DEL_ID | CP_ID | ID | QUANTITY | FP_ID | RESULT |
I need to populate the result column by using the Quantity and FP_ID columns by concatenating the FP_ID value to itself, and do so as many times as the value of QUANTITY.
So RESULT = FP_ID concatenated to itself QUANTITY times.
If QUANTITY is 3 and FP_ID is 23 then the result should be 232323
I need to do an insert that inserts this result for each row based on this logic.
How do I do this in SQL?

It should be computed column....
I mean I should be declared as it is based on other two columns
if you want to add after creation of table
ALTER TABLE tblResults
ADD Final_Result as replicate(FP_ID ,Quantity)
else
while creation
Create table tblResults
(.......ur columns..... , Final_Result as replicate(FP_ID ,Quantity))
you no need to give data for this column, It will automatically loaded when the data is loaded into table "tblResults"
NOTE: If any value is null then the Final_Result value will also be NULL

I have edited my answer as below:
Please execute the below query to create a Function:
CREATE FUNCTION [dbo].[ConcatenateString]
(
#FP_ID INT,
#QUANTITY INT
)
RETURNS
NVARCHAR(MAX)
AS
BEGIN
DECLARE #ConcatenatedString NVARCHAR(MAX), #ConvertedFP_ID NVARCHAR(100)
SET #ConcatenatedString =''
SET #ConvertedFP_ID = CONVERT(varchar(100),#FP_ID)
WHILE #QUANTITY >= 1
BEGIN
SELECT #ConcatenatedString = #ConcatenatedString+#ConvertedFP_ID
SET #QUANTITY = #QUANTITY - 1
END
RETURN #ConcatenatedString
END
GO
And you can call the Function in the INSERT script:
INSERT INTO tblResults(DEL_ID,CP_ID,ID,QUANTITY,FP_ID,RESULT)
VALUES(1,2,3,4,5,(SELECT dbo.ConcatenateString(4,5) AS ConcatnatedValue))

Related

SQL matching with rest of the columns if any of the where condition parameter is missing

Here is my table structure:
ID cid Name Course Interval
1 1 KB Y 2
2 1 TB Y 3
3 2 BK N 1
I need to write a query which returns all rows with matching condition.
if at all any of the parameter is null or not provided then i need to return all of the matching rows.
In my select query if my parameters are (cid ==1 and Name== null and course ==Y or (cid ==1 and course ==Y ) then I need to return rows with id
1 and 2.
What exactly I need is this:
If I get all the matching record then i can take interval corresponding to the record. Else I need to take average interval of the matching record
Is this what you are after? Its a variable number or arguments - in my case the parameters are explicitly defined, yours may be passed in from a stored proc etc.
-- Create the table
create table #t(ID int, cid int, Name char(2), Course char(1), Interval int)
insert #t values (1,1,'KB','Y',2)
,(2,1,'TB','Y',3)
,(3,2,'BK','N',1)
-- Declare the arguments
declare #cid int
declare #name char(2)
declare #course char(1)
-- Set one or more arguments
set #cid=1
set #name=null
set #course='Y'
select AVG(convert(decimal(5,2),interval)) from #t
where isnull(#cid,cid)=cid
and isnull(#name,name)=name
and isnull(#course,course)=course

Trouble updating log with triggers using SQL Server

I am trying to create a trigger with a higher difficulty that would let me create a log after updating rows in alumns table
| Alumn_ID | Name | Courses | Favourite_Course
1 Peter 5 Math
And this would be the result if for example someone updated the number of courses from 5 to 6.
| Log_ID | Alumn_ID | Note | NoteID | Change_Date | Last_Change_Date
1 1 Fields were Updated Note 1 2018-04-23 00:00:00.000 2018-03-23 00:00:00.000
Here is my current trigger
ALTER TRIGGER [LOG]
ON ALUMNS
AFTER UPDATE
AS
BEGIN
DECLARE #Note VARCHAR(50)
DECLARE #Alumn_ID varchar;
SELECT #Alumn_ID= INSERTED.Alumn_ID FROM INSERTED
SET #Note = 'Fields were updated'
INSERT INTO Alumn_Log (Log_ID, Alumn_ID, Note, NoteID, Change_Date)
SELECT Log_ID, i.Alumn_ID, #Note, NoteID, GETDATE(); FROM INSERTED i
END
My problem is:
How do i create the Log ID and the Note ID that i can't take from INSERTED i?
My second problem is, how do i insert the current date? when i try to execute the query it tells me that i can't use that variable in INSERTS.
My third problem, is how can i put the "Last change date"?
Fourth, is there a way to type an specific Note for example if only the name was changed it should say "Name was changed"?
Finally, The Note ID would be Varchar not identity and every note ID needs to be different
This is the current and only error that's preventing me from running the Query:
This is what i get Msg 273, level 16, state 1, procedure Log_Trigger, line 19 [Batch Start Line 0] me time stamp Use INSERT with a list of columns to exclude the timestamp column or insert DEFAULT in the timestamp column.
Here is how I would approach it.
How do i create the Log ID and the Note ID that i can't take from
INSERTED i?
The Log Id can be an AutoIdentity column. An INT column with IDENTITY INSERT.
The Note ID can be an Auto Incremented Computed column (shown in the code below). You would probably need to introduce a new column that serves as a prefix.
My second problem is, how do i insert the current date? when i try to
execute the query it tells me that i can't use that variable in
INSERTS.
GETDATE()?
My third problem, is how can i put the "Last change date"?
You can have a join with INSERTED and get the value from the log from a previous row. Shown in the code.
Fourth, is there a way to type an specific Note for example if only
the name was changed it should say "Name was changed"?
That would depend on finding the nature of the update on which column. This is more of a business question than a technical question.
Finally, The Note ID would be Varchar not identity and every note ID needs to be different
Now, the code (the entire schema)
CREATE TABLE LOG(
Log_ID INT IDENTITY(1, 1) NOT NULL,
Alumn_ID INT,
NOTE VARCHAR(200),
PREFIX VARCHAR(30),
NOTEID AS([PREFIX] + RIGHT('0000000' + CAST(Log_ID AS VARCHAR(7)), 7)) PERSISTED,
CHANGEDATE DATETIME,
LASTCHANGEDATE DATETIME
);
CREATE TABLE ALUMN(
Alumn_ID INT,
NAME VARCHAR(50),
COURSES INT,
FAVORITE_COURSE VARCHAR(50)
);
CREATE TRIGGER[trg_LOG]
ON ALUMN
AFTER UPDATE
AS
BEGIN
DECLARE #Note VARCHAR(50)
--DECLARE #Alumn_ID VARCHAR(50)
DECLARE #Lastchange DATETIME
--SELECT #Alumn_ID = INSERTED.Alumn_ID FROM INSERTED
SET #Note = 'Fields were updated'
SELECT #Lastchange = CHANGEDATE FROM LOG l
INNER JOIN INSERTED i ON l.Alumn_ID = i.Alumn_ID
--INNER JOIN ALUMN
INSERT INTO LOG(Alumn_ID, Note, Prefix, CHANGEDATE, LASTCHANGEDATE)
SELECT i.Alumn_ID, #Note, 'AUP', GETDATE(), #Lastchange FROM INSERTED i
END
how do i insert the current date? when i try to execute the query it
tells me that i can't use that variable in INSERTS.
SELECT Log_ID, i.Alumn_ID, #Note, NoteID, GETDATE(); FROM INSERTED i
Take the semi-colon out of the line above.
SELECT Log_ID, i.Alumn_ID, #Note, NoteID, GETDATE() FROM INSERTED i

How to autocomplete SQL field based on same row fields

QUESTION HAS BEEN UPDATED:Let's say I have two tables:Table1
ID_Ticket | Ticket_Quantity | Total_Price(Calculated field)
--------------------------------------------
2 | 5 | x
1 | 3 | y
Table2
ID_Ticket | Ticket_Price
------------------------
1 | 4.5
2 | 5
I want to prevent the user of the database to fill the field of Total_Price (via Edit Top 200 Rows or queries), instead I want it to be calculated as Ticket_Price * Ticket_Quantity and be inserted automatically on that row. In this case, x should be 25 and y should be 13.5 (the values should be insterted automatically once Ticket_Quantity and Ticket_Price are filled for that row)I wrote a function like this:
CREATE FUNCTION Multiply(#x DECIMAL(19,4), #y DECIMAL (19,4))
RETURNS DECIMAL(19,4)
AS
BEGIN
SELECT #x * Ticket_Price
FROM Table2
WHERE ID_Ticket = #y
ENDBut there is an error:Select statements included within a function cannot return data to a client Also when I want to add the calculated field based on the function:ALTER TABLE Purchases
ADD Total_Price AS Multiply(Table2.Ticket_Price,Ticket_Quantity); The query doesn't execute and gives me this error:
The multi-part identifier "Product.Prod_Price" could not be bound.
How should I call the values from Table2 and fix the Multiply function?
I found a solution, so I'll post it for future readers who have the same problem:
In the Object Explorer (left panel) go to this path:
Databases --> <your_database_name> --> programmability --> functions
Right-click on the Functions folder and select New --> Scalar-valued function
Paste the following function script (replace < variables > with those that correspond to your database):
CREATE FUNCTION dbo.Multiply(#id INT, #price DECIMAL(19,4))
--or (#x float, #y money) depending on the type of your columns you have
RETURNS DECIMAL(19,4)
--RETURNS <data_type_of_the_calculated_column_you_want>
AS
BEGIN
RETURN
(SELECT #price * Ticket_Price
--SELECT #<second_argument/column_name_of_Table1>*<column_name_of_Table2>
FROM Table2
--FROM <your_Table2_name>
WHERE ID_Ticket = #id)
--WHERE <unique/PrimaryKey_Column_to_identify_the_row_in_Table2>
-- = #<ForeignKey_Column_to_identify_the_row_in_Table2>
END
And execute it.
Now Create a new query (Ctrl+N) to add the calculated column in Table1, and copy-paste the following query:
ALTER TABLE Table1
--ALTER TABLE <your_Table1_name>
ADD Total_Price AS dbo.Multiply(ID_Ticket,Ticket_Quantity);
--ADD <name_of_the_calculated_row_you_like> AS
-- dbo.<Function_Name>(<id_column_name_of_Table2>,<column_name_from_Table1>)
Execute the query.
Now the calculated column should be the multiplication of the columns of Table1 and Table2

Assigning Value along with Data Retrieval

Is there a way to combine assigning a value to a variable and Selecting a column in sql. I need to compute and select a column in a table based on the variable. The variable's value changes based on another column in the table.
var #BeginValue
Columns in table : ReducedBy
My initial begin value is stored in #BeginValue. The table has reducedBy which is a factor by which my begin value should be reduced. So when i select, beginvalue for the first recored would be #BeginValue and the #EndValue should be #BeginValue = #BeginValue - reducedBy. It continues like this, as many times as the number of records in my table.
Result set must be like this:
#Begin = 10
Begin End ReducedBy
10 8 2
8 6 2
6 5 1
Is there a way with which i can achieve this without using a cursor or with multiple update statements.
You can't assign in a query that returns a result set. The closest you can get is to store the result in a table variable. Then you can both do computations against that table, and return it as a result set:
-- Store results in table variable
declare #tbl table (id int, col1 int, ...)
insert #tbl
(id, col1, ...)
select id
, col1
, ...
from ... your query here ...
-- Assign variable
select #YourVariable = ... your computation here ...
from #tbl
-- Return result set
select *
from #tbl
If your question is
Can I do..
SELECT #a = field, field2 from table
and get a resultset and set the value of #a?
Then the answer is no, not in a single statement.

How to create conditional unique constraint

Having a table:Table1 in which a column Code accepts nullables values how can we insure that values are unique for non nullable values except for codes that start with 'A' which can be duplicated maximum twice?
Table1
Id | Code
----------
1 | NULL --[ok]
2 | A123 --[ok]
3 | A123 --[ok]
4 | B100 --[ok]
5 | C200 --[ok]
6 | B100 --[not ok already used]
7 | NULL --[ok]
What i have tried is creating an indexed view, the solution work fine for NULL values but not for the second case i mentioned (skipped actualy)
Create view v_Table_unq with schemabinding as(
select code from
dbo.Table1
where code is not null and code not like 'A%'
)
go
create unique clustered index unq_code on v_Table_unq(code)
Thanks for help
Table Creation
CREATE TABLE CheckConstraint
(
Name VARCHAR(50),
)
GO
Function Creation
create FUNCTION CheckDuplicateWithA() RETURNS INT AS BEGIN
DECLARE #ret INT =0 ;
SELECT #ret = IsNull(COUNT(Name), 0) FROM CheckConstraint WHERE Name like '[A]%' group by Name having COUNT(name) >= 1;
RETURN IsNUll(#ret, 0);
END;
GO
create FUNCTION CheckDuplicateOtherThenA() RETURNS INT AS BEGIN
DECLARE #ret INT =0 ;
SELECT #ret = IsNull(COUNT(Name), 0) FROM CheckConstraint WHERE Name not like '[A]%' group by Name having COUNT(name) >= 1;
RETURN IsNUll(#ret, 0);
END;
GO
Constraints
alter TABLE CheckConstraint
add CONSTRAINT CheckDuplicateContraintWithA CHECK (NOT (dbo.CheckDuplicateWithA() > 2));
go
alter TABLE CheckConstraint
add CONSTRAINT CheckDuplicateConmstraintOtherThenA CHECK (NOT (dbo.CheckDuplicateOtherThenA() > 1));
go
Result Set
insert into CheckConstraint(Name)Values('b') -- Passed
insert into CheckConstraint(Name)Values('b') -- Failed
insert into CheckConstraint(Name)Values('a') -- Passed
insert into CheckConstraint(Name)Values('a') -- Passed
insert into CheckConstraint(Name)Values('a') -- Failed
Why would you want a unique contraint? Why cant add this logic in the proc which inserts the data in the table?If you do not have a single point of insertion/updation etc?Why cant put it in instead of or after trigger?That would be much better as you can handle it well and could return proper errror messages.This will have less overhead than having a index view which will add to overhead.If you need unique constraint for the records which doesnt start with 'A' then you can have a persisted column and have a unique constraint on that.
Off course you will have overhead of having persisted computed column with index..But if you just need unique contsraint you can use that.For values which starts with 'A' this could be a null value.