I am fairly new to SQL. I have a table with several columns: item ID, purchased price and price sold. I need to write a sql statement to return the difference between the purchased price and price sold along with the item ID
Thanks!
Select itemID, purchasePrice - soldPrice
from myTable;
This will return all ItemID's, and the difference in the prices for each. You can add a where clause to filter.
Here is an example:
declare #itemID varchar(55), #purchasePrice float, #salePrice float
set #itemID = 'Shirt'
set #purchasePrice = 65.50
set #salePrice = 78.98
select #itemID, #salePrice - #purchasePrice
Related
I'm having trouble writing a function with a DATEDIFF inside it to use in a computed column.
I have 2 tables:
Transaction
tID
cID
carID
eID
tDate
PickupDate
ReturnDate
Car
carID
Make
Model
Type
Year
[Data][1]
I need to add an Amount_Due column to the Transaction table that calculates price * number of days.
I know that I need to write a function with a DATEDIFF inside as you can't reference other tables in a computed column. I'm new to SQL and this is the first function I've attempted to write. Here's what I have so far.
CREATE FUNCTION TransactionAmountDue(#DateDiff INT, #carID INT)
RETURNS MONEY
AS
BEGIN
DECLARE #price decimal(10,2)
SELECT #price = Price FROM Car AS TP
WHERE TP.carID = #carID
SELECT #DateDiff = DATEDIFF(day, [Transaction].PickupDate, [Transaction].ReturnDate)
RETURN #DateDiff * #price
END
ALTER TABLE [Transaction] ADD Amount_Due AS
[1]: https://i.stack.imgur.com/w20jv.png
I am struggling with calling a function with in a view to create a list of sales details including a column for GST amount and the total sale price (original price plus GST) for each individual sale.
Here is the function I have created:
CREATE PROCEDURE dbo.sp_ReturnTaxedPrice
#ProductID int,
#GST float,
#GSTPrice float output
AS
BEGIN
DECLARE #Price float
SET #Price = (SELECT Price FROM Products WHERE ProductID = #ProductID)
SET #GSTPrice = #Price * (1 - #GST)
END
And here is the view I would like to use that function in to add two columns at the end of the table to display the GST amount and total price amount (original price plus GST) for each sale:
CREATE VIEW vw_SaleDetails
AS
SELECT
Sales.SaleNo,
Sales.SaleDate,
Customer.FirstName,
Customer.LastName,
Category.Category,
Products.ProductDescription,
Type.Type,
Products.Year,
Products.Price
FROM Category JOIN Customer ON Category.CategoryID = Customer.CategoryID
JOIN Sales ON Customer.CustomerID = Sales.CustomerID
JOIN SalesProducts ON Sales.SaleNo = SalesProducts.SaleNo
JOIN Products ON Products.ProductID = SalesProducts.ProductID
JOIN ProductType ON Products.ProductID = ProductType.ProductID
JOIN Type ON Type.TypeID = ProductType.TypeID
You want a function, not a procedure:
CREATE FUNCTION dbo.sp_ReturnTaxedPrice (
#ProductID int,
#GST float
) RETURNS float
AS
BEGIN
DECLARE #Price float;
SET #Price = (SELECT Price FROM Products WHERE ProductID = #ProductID);
SET #GSTPrice = #Price * (1 - #GST);
RETURN(#GSTPrice);
END;
Then, you can do:
select . . .
dbo.sp_ReturnTaxedPrice(#ProductID, #GST)
. . .
Now some comments:
Putting this logic in a user-defined function (or stored procedure) adds a lot of overhead. You should just put the arithmetic in the code.
float is not the right data type for monetary values. Use MONEY or DECIMAL/NUMERIC.
If you don't understand why, learn about fixed-point versus floating-point types.
I have a table as below:
The first record Amount and TotalAmount are same
In the second record Amount is added from first row and current and TotalAmount is added
And so on....
Now if I update the second row from 1.25 to 2, then the TotalAmount for all subsequent records should be changed.
I need an update query for this.
I have seq_no and row no as reference and field Type is the reference
Ideally you should create a view or stored procedure that performs a running total, this is an example of one method using a subquery:
SELECT
Type,
Amount ,
Total =
(
SELECT SUM(Amount)
FROM SomeTable B
WHERE B.Type=A.Type AND B.RowNum <= A.RowNum
)
FROM SomeTable A
This is just one method (not necessarily the best). I would suggest you google 'Running totals in SQL' and familiarise yourself with the explanation of this and other methods their pros, cons and performance implications of each.
One question, what version of SQL server are you using?
If you can use row number as reference than you can try following query but storing totals in table is bad idea as mentioned in comment:
DECLARE #Temp TABLE
(
Amount float,
TotalAmount float,
Rownum int
)
INSERT INTO #Temp VALUES (1.25,1.25,1),(1.25,2.50,2),(10,12.50,3)
DECLARE #PreviousAmount AS FLOAT
SELECT #PreviousAmount = Amount FROM #Temp WHERE Rownum=1
DECLARE #NewAmount AS FLOAT = 2
UPDATE #Temp SET TotalAmount = TotalAmount - #PreviousAmount WHERE Rownum>=1
UPDATE #Temp SET Amount=#NewAmount, TotalAmount = TotalAmount + #NewAmount WHERE Rownum=1
UPDATE #Temp SET TotalAmount = TotalAmount + #NewAmount WHERE Rownum>1
SELECT * FROM #Temp
If you want to use triggers(which is not recommended).you can use this:
create trigger trigger_name
for update
as
declare #count int= (select count(*) from table)
declare #a int =1
while(#a<#count)
begin
update table
set total_amount=(select amount from table where row_number=#a) + (select amount from table where row_number=#a-1 )
where row_number!=1
set #a=#a+1
end
Go
I have a table orderDetails that contains the products of an order
productId
color
size
quantity
and a table stock
productId
size
color
stock
When a order is completed I use this query to insert the items in the table orderDetails
INSERT INTO orderDetail(orderId, productId, productColor, productSize, productQuantity , cost productName)
SELECT
#orderId, products_translations.id, cart.productColor, cart.productSize,
cart.productQuantity, cart.cost, products_translations.name
FROM cart
INNER JOIN products_translations ON cart.productID = products_translations.id
WHERE
(cart.cartId = #cartId) AND
(products_translations.language = 1)
Then I have a trigger on table orderDetails:
ALTER TRIGGER [dbo].[scalaProdotti]
ON [dbo].[orderDetail]
FOR INSERT
AS
DECLARE #size int
DECLARE #color char(6)
DECLARE #quantity int
DECLARE #product int
BEGIN
SELECT #size = productSize FROM inserted
SELECT #color = productColor FROM inserted
SELECT #quantity = productQuantity FROM inserted
SELECT #product = productId FROM inserted
UPDATE stock SET quantity = quantity - #quantity WHERE size=#size AND color=#color AND product=#product
END
With this trigger I want to decrease the stock, but only the first product is affected, the other quantities remain the same.
What am I missing?
Thank you.
The main point is: you're assuming that the trigger will be called for each row being inserted - this is not the case.
Your trigger will be called once per statement - but that statement can insert mulitple rows at once.
In such a case, the Inserted table inside the trigger will contain multiple rows and your statements:
SELECT #size = productSize FROM inserted
SELECT #color = productColor FROM inserted
SELECT #quantity = productQuantity FROM inserted
SELECT #product = productId FROM inserted
will fail or will happen to select only the first row inserted and disregard the rest of the inserts.
You need to rewrite your trigger to cope with the fact that Inserted can contain multiple inserted rows at the same time
Your code in the trigger should look something like this:
UPDATE stock
FROM Inserted i
SET
stock.quantity = quantity - i.quantity
WHERE
stock.size = i.size
AND stock.color = i.color
AND stock.product = i.product
Is there any alternate way to create stored procedure without putting all query in one long string if criteria of WWHERE clause can be different.
Suppose I have Orders table I want to create stored procedure on this table and there are three column on which I wnat to filter records.
1- CustomerId, 2- SupplierId, 3- ProductId.
If user only give CustomerId in search criteria then query should be like following
SELECT * FROM Orders WHERE Orders.CustomerId = #customerId
And if user only give ProductId in search criteria then query should be like following
SELECT * FROM Orders WHERE Orders.ProductId = #productId
And if user only all three CustomerId, ProductId, and SupplierId is given then all three Ids will be used in WHERE to filter.
There is also chance that user don't want to filter record then query should be like following
SELCT * FROM Orders
Whenever I have to create this kind of procedure I put all this in string and use IF conditions to check if arguments (#customeId or #supplierId etc) has values.
I use following method to create procedure
DECLARE #query VARCHAR(MAX)
DECLARE #queryWhere VARCHAR(MAX)
SET #query = #query + 'SELECT * FROM Orders '
IF (#originationNumber IS NOT NULL)
BEGIN
BEGIN
SET #queryWhere =#queryWhere + ' Orders.CustomerId = ' + CONVERT(VARCHAR(100),#customerId)
END
END
IF(#queryWhere <> '')
BEGIN
SET #query = #query+' WHERE ' + #queryWhere
END
EXEC (#query)
Thanks.
You could pass NULL for fields that you don't want to include in your WHERE-clause and check for NULL in the query:
Select customerId, productId, supplierId
From Orders
Where ( customerId = #customerId Or #customerId IS NULL )
And ( productId = #productId Or #productId IS NULL )
And ( supplierId= #supplierId Or #supplierId IS NULL )
Don't use SELECT *, always list the columns you actually need.
Select CustomerId, ProductId, SupplierId
From Orders
Where CustomerId = ISNULL( #customerId, CustomerId )
And ProductId = ISNULL( #productId, ProductId )
And SupplierId= ISNULL( #supplierId, SupplierId )
Erland Sommarskog has a great pair of articles, describing various search techniques and trade offs (one for SQL 2008, one for earlier versions)