I'm setting up a storekeeping program in which I have 2 tables, one for products and another for materials.
In the products table, each product has several materials. Is there any way to select these rows and decrement materials availability?
I tried to use a foreach loop but I couldn't implement it and store each rows data
CREATE TABLE materials
(
materialID INT PRIMARY KEY IDENTITY,
materialName NVARCHAR(100) NULL,
materialAmount INT NULL,
)
CREATE TABLE productStack
(
ID INT PRIMARY KEY IDENTITY,
productsID INT NULL,
materialID INT NULL,
amount INT NULL
)
GO;
CREATE PROCEDURE updateMaterials
(#ID INT,
#AMOUNT INT)
AS
BEGIN
UPDATE materials
SET materialAmount = (materialAmount - #AMOUNT)
WHERE materialID = #ID
END
You could use a temp table and while loop such as :
SELECT * INTO #TEMP_A FROM PRODUCTSTACK
DECLARE #ID INT,#AMOUNT INT
WHILE EXISTS(SELECT * FROM #TEMP_A)
BEGIN
SET #ID = (SELECT TOP 1 ID FROM PRODUCTSTACK)
SET #AMOUNT = (SELECT TOP 1 AMOUNT FROM PRODUCTSTACK WHERE ID = #ID)
EXEC UPDATEMATERIALS #ID,#AMOUNT
DELETE FROM #TEMP_A WHERE ID = #ID
END
As we have no sample to base this on, this is a guess. Like I said, however, seems like a table-type parameter would do this:
CREATE TYPE dbo.MaterialAmount AS table (ID int, Amount int);
GO
CREATE PROC dbo.UpdateMaterials #Materials dbo.MaterialAmount READONLY AS
BEGIN
UPDATE M
SET materialAmount = MA.Amount
FROM dbo.materials M
JOIN #Materials MA ON M.materialID = MA.ID;
END;
GO
--Example of usage:
DECLARE #Materials dbo.MaterialAmount;
INSERT INTO #Materials
VALUES(1,100),
(5,20);
EXEC dbo.UpdateMaterials #Materials;
Can I run 2 queries in one stored procedure ?
CREATE PROCEDURE AddProd
#Store_Name varchar(50),
#Price int,
#Prod_Name varchar(50),
#Qty int,
#ProductDescription varchar(50),
#RatingSum int,
#RatingCount int,
#ProductImage varchar(50),
#Prod_Date date,
AS
BEGIN
SELECT S.Store_ID
FROM Store S
WHERE StoreName=#StoreName
INSERT INTO Product (Store_ID, Price, Prod_Name, Qty, ProductDescription, RatingSum, RatingCount, ProductImage, Prod_Date)
VALUES (S.Store_ID, #Price, #Prod_Name, #Qty, #ProductDescrpition, #RatingSum, #RatingCount, #ProductImage, #Prod_Date)
END
GO
For this code above, I want retrieve a STORE_ID by giving the STORE_NAME the user give as a parameter.
I want to use this STORE_ID in the INSERT statement.
Can I do this ?!
AKA, is the S.store_ID returned from the first query, the same as that one I used in "Values" ?
Technically, you can do this in a single query:
INSERT INTO Product
(Store_ID, Price, Prod_Name, Qty, ProductDescription, RatingSum, RatingCount, ProductImage, Prod_Date)
SELECT S.Store_ID, #Price,#Prod_Name,#Qty,#ProductDescription,#RatingSum,#RatingCount,#ProductImage,#Prod_Date
FROM Store S
WHERE StoreName=#StoreName
I don't have test data handy to check, but you may have to give the appropriate names to each of the columns in the select clause from that query, instead of just the variable names. The only other reason this might not work is if you also wanted to return the selected storeID from the stored procedure, but even in that case you can just add an OUTPUT clause:
INSERT INTO Product
(Store_ID, Price, Prod_Name, Qty, ProductDescription, RatingSum, RatingCount, ProductImage, Prod_Date)
OUTPUT S.Store_ID
SELECT S.Store_ID, #Price,#Prod_Name,#Qty,#ProductDescription,#RatingSum,#RatingCount,#ProductImage,#Prod_Date
FROM Store S
WHERE StoreName=#StoreName
But for the title question, the answer is affirmative; you can execute multiple statements inside a single stored procedure.
unless you want to return the storeID from the sp remove that query and put it into the insert
INSERT INTO Product (Store_ID,Price,Prod_Name,Qty,ProductDescription,RatingSum,RatingCount,ProductImage,Prod_Date)
values (
(SELECT S.Store_ID FROM Store S WHERE StoreName=#StoreName),
#Price,#Prod_Name,#Qty,#ProductDescrpition,#RatingSum,#RatingCount,#ProductImage,#Prod_Date)
If StoreID is unique for each store name you can store it in a variable and use it in your insertion
CREATE PROCEDURE AddProd
#Store_Name varchar(50),
#Price int,
#Prod_Name varchar(50),
#Qty int,
#ProductDescription varchar(50),
#RatingSum int,
#RatingCount int,
#ProductImage varchar(50),
#Prod_Date date,
AS
BEGIN
DECLARE #StoreID [DataType]
SELECT #StoreID = S.Store_ID
FROM Store S
WHERE StoreName=#StoreName
INSERT INTO Product (Store_ID,Price,Prod_Name,Qty,ProductDescription,RatingSum,RatingCount,ProductImage,Prod_Date)
values (#StoreID,#Price,#Prod_Name,#Qty,#ProductDescrpition,#RatingSum,#RatingCount,#ProductImage,#Prod_Date)
END
GO
In any scenario you can use the following
CREATE PROCEDURE AddProd
#Store_Name varchar(50),
#Price int,
#Prod_Name varchar(50),
#Qty int,
#ProductDescription varchar(50),
#RatingSum int,
#RatingCount int,
#ProductImage varchar(50),
#Prod_Date date,
AS
BEGIN
INSERT INTO Product (Store_ID,
Price,
Prod_Name,
Qty,
ProductDescription,
RatingSum,
RatingCount,
ProductImage,
Prod_Date
)
SELECT
S.Store_ID
#StoreID,
#Price,
#Prod_Name,
#Qty,
#ProductDescrpition,
#RatingSum,
#RatingCount,
#ProductImage,
#Prod_Date
FROM Store S
WHERE StoreName=#StoreName
END
GO
I'm working on a cascading insertion where a stored procedure should return an id of the inserted row. This would not be a problem if the id of the table was an int. However, the id is a varchar and therefore I cannot use SCOPE_IDENTITY().
This is my procedure so far:
CREATE PROCEDURE NEW_ARTICLE
#id varchar(50) OUTPUT,
#name varchar(100),
#articleNr varchar(50),
#gategory varchar(50),
#containerId varchar(50),
#contPerContainer int,
#pictureId varchar(50)
AS
SET NOCOUNT OFF
INSERT INTO nextlabel.[Article] (name, article_nr, category, container_id, count_per_container, picture_id )
VALUES (#name, #articleNr, #gategory, #containerId, #contPerContainer, #pictureId)
SET #id = SCOPE_IDENTITY()
Where the last row is not correct since the column id is a varchar.
How can I return the id?
Try this:
CREATE PROCEDURE NEW_ARTICLE
#id varchar(50) OUTPUT,
#name varchar(100),
#articleNr varchar(50),
#gategory varchar(50),
#containerId varchar(50),
#contPerContainer int,
#pictureId varchar(50)
AS
SET NOCOUNT OFF
SET #id = newid()
INSERT INTO nextlabel.[Article] (id, name, article_nr, category, container_id, count_per_container, picture_id)
VALUES (#id, #name, #articleNr, #gategory, #containerId, #contPerContainer, #pictureId)
GO
ALTER procedure [dbo].[staffscorecard]
#STAFF_ID INT = NULL
as
select
count(STAFF_ID) as countexel
from
TbStudentSurvey
where
FEEDBACK = 'excellent'
and STAFF_ID = ISNULL(#STAFF_ID, STAFF_ID)
select
Score as scoreexel
from
TbStaffScoreMaster
where
Status = 'Excellent'
exec [dbo].[staffscorecard]
GO
CREATE TABLE #temp ( countexel int, scoreexel int)
GO
INSERT INTO #temp (countexel , scoreexel)
EXEC [dbo].[staffscorecard]
GO
SELECT *
FROM #temp
GO
For a given staffid to calculate countexel and scoreexel you can re-write your stored procedure as:
create table TbStudentSurvey (STAFF_ID int,FEEDBACK varchar(20));
insert into TbStudentSurvey values (1,'excellent'),(1,'excellent'),(2,'excellent');
create table TbStaffScoreMaster (Score int,[Status] varchar(20));
insert into TbStaffScoreMaster values(100,'Excellent');
Go
create procedure [dbo].[staffscorecard]
#STAFF_ID INT = NULL,
#countexel int output,-- Explicitly declare output variables to fetch these values
#scoreexel int output
as
Begin
select
#countexel = count(STAFF_ID)
from
TbStudentSurvey
where
FEEDBACK = 'excellent'
and STAFF_ID = ISNULL(#STAFF_ID, STAFF_ID)
select
#scoreexel = Score
from
TbStaffScoreMaster
where
Status = 'Excellent'
End
GO
and then instead of using a temp table use a table variable because when you use temp tables,the table has to match the exact column layout as of the stored procedure.
--CREATE TABLE #temp (countexel int, scoreexel int)
--GO
--Create a table variable:
declare #temp table (countexel int, scoreexel int)
declare #countexel int, #scoreexel int,#STAFF_ID int;
--set value of staff Id for which you want to get countexel and scoreexel.
set #STAFF_ID = 1;
EXEC [dbo].[staffscorecard] #STAFF_ID ,#countexel output,#scoreexel output
INSERT #temp values (#countexel ,#scoreexel);
SELECT *
FROM #temp
GO
Method 2:
You can also write as:
alter procedure [dbo].[staffscorecard]
#STAFF_ID INT = NULL
as
Begin
select
count(STAFF_ID) as countexel , Score as scoreexel
from
TbStudentSurvey TSS
inner join TbStaffScoreMaster TSM on TSM.Status = TSS.FEEDBACK
where
FEEDBACK = 'excellent'
and STAFF_ID = ISNULL(#STAFF_ID, STAFF_ID)
group by STAFF_ID,Score
End
GO
declare #temp table (countexel int, scoreexel int)
declare #STAFF_ID int;
set #STAFF_ID = 1;--set value of staff Id for which you want to get countexel and scoreexel.
INSERT #temp EXEC [dbo].[staffscorecard] #STAFF_ID
SELECT *
FROM #temp
GO
Hope this helps!!
Im doing a reservation application and was wondering how would i handle the following scenario; if a booking has 2 or more "extra" items on it how do i create a SP or a trigger even to handle this? the SP i have now works fine for a booking with a single extra item on it. Im i making any sense?
ALTER PROCEDURE [dbo].[CreateBooking]
#DateFrom datetime,
#DateTo datetime,
#RoomID int,
#PersonID int,
#ProductID int,
#OrderAmount int
AS
BEGIN TRANSACTION
SET NOCOUNT ON;
INSERT INTO booking(created_on, startdate, enddate, room_id, person_id)
VALUES (getdate(), #DateFrom, #DateTo, #RoomID, #PersonID)
IF ##error <> 0
ROLLBACK TRANSACTION
ELSE
INSERT INTO booking_details (booking_id,prod_id,order_amount)
VALUES (SCOPE_IDENTITY(), #ProductID, #OrderAmount)
COMMIT TRANSACTION
You can pass an xml parameter then loop through it and write them.
CREATE PROCEDURE
SelectByIdList(#productIds xml) AS
DECLARE #Products TABLE (ID int)
INSERT INTO #Products (ID) SELECT
ParamValues.ID.value('.','VARCHAR(20)')
FROM #productIds.nodes('/Products/id')
as ParamValues(ID)
SELECT * FROM
Products INNER JOIN
#Products p ON Products.ProductID = p.ID