How to autocomplete SQL field based on same row fields - sql

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

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

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

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))

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.

Update multiple rows with different values in SQL

I have a table like this:
SKU Size
A 10
B 10
C 10
D 10
E 10
F 10
G 10
I want to change it to:
SKU Size
A 20
B 10
C 30
D 10
E 80
F 10
G 60
I have more than 3000 rows of records to update. How can I do that with SQL update command ?
UPDATE T
SET Size = CASE SKU
WHEN 'A' THEN 20
WHEN 'B' THEN 10
WHEN 'C' THEN 30
WHEN ...
END
Or there may be a formula for calculating the size, but you've failed to give it in your question (Or we may have to switch to a more complex CASE expression, but again, too little detail in the question).
Create a table with the mapping of SKU to new size; update the master table from that.
Many dialects of SQL have a notation for doing updates via joined tables. Some do not. This will work where there is no such notation:
CREATE TABLE SKU_Size_Map
(
SKU CHAR(16) NOT NULL,
Size INTEGER NOT NULL
);
...Populate this table with the SKU values to be set...
...You must have such a list...
UPDATE MasterTable
SET Size = (SELECT Size FROM SKU_Size_Map
WHERE MasterTable.SKU = SKU_Size_Map.Size)
WHERE SKU IN (SELECT SKU FROM SKU_Size_Map);
The main WHERE condition is need to avoid setting the size to null where there is no matching row.
You can probably also do it with a MERGE statement. But the key insight for any of these notations is that you need a table to do the mapping between SKU and size. You either need a table or you need an algorithm, and the sample data doesn't suggest an algorithm.
Make use of OpenXML to resolve your issue
example
declare #i int
exec sp_xml_preparedocument #i output,
'<mydata>
<test xmlID="3" xmlData="blah blah blah"/>
<test xmlID="1" xmlData="blah"/>
</mydata>'
insert into test
select xmlID, xmlData
from OpenXml(#i, 'mydata/test')
with (xmlID int, xmlData nvarchar(30))
where xmlID not in (select xmlID from test)
update test
set test.xmlData = ox.xmlData
from OpenXml(#i, 'mydata/test')
with (xmlID int, xmlData nvarchar(30)) ox
where test.xmlID = ox.xmlID
exec sp_xml_removedocument #i
Just do...
UPDATE [yourTable] SET Size = 20 WHERE SKU = 'A'
And do this for all values you want to change...
Well, if you don't have a formula to calculate your Sizes, and you don't have a file or an Excel sheet with the data that you can massage into your table, you'll just have to get some luckless intern to type something like
UPDATE <table> SET Size = <value> WHERE SKU = '<key>'
3000 times.
If you are that intern, I'd suggest giving us a little more information...
Since you wanted to change the whole column, drop that particular column by using this:
ALTER TABLE table_name
DROP COLUMN column_name;
then create a new column using:
ALTER TABLE table_name
ADD column_name varchar(80);