I need to make a SQL stored procedure that will take two input parameters ( id from table ‘users’ and id from table ‘sales’ ) and then if value of column ‘coupons’ (table ‘users’) is greater then 0, it increases value for 1 in column ‘numOfSales’(table ‘sales’) and decreases value for 1 in column ‘coupons’.
I tried this :
CREATE PROCEDURE usp_makesale
#id_sales int NOT NULL,
#id_users int NOT NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT users.coupons, sales.numOfSales
IF (coupons > 0)
BEGIN
SET coupons - 1;
SET numOfSales + 1;
END
How to declare those variables properly ?
You should declare the variables like so:
DECLARE #coupons AS INT
SELECT #coupons = coupons FROM users WHERE users.id = #id_users
DECLARE #numOfSales AS INT
SELECT #numOfSales = numOfSales FROM sales WHERE sales.id = #id_sales
However you also haven't correctly written an update statement to update the values in your columns. You require something like:
UPDATE users
SET coupons = coupons - 1
WHERE users.id = #id_users
UPDATE sales
SET numOfSales = numOfSales + 1
WHERE sales .id = #id_sales
Related
I have a stored procedure where a populate a base table with key fields and then loop through that table to get those key fields to requery a source data table to get detailed counts. The issue I am having is that when there are a lot of rows in the base table, the SP takes a long time to run. I've loaded the source data into temp tables and created index's and made the base table a temp table with an index as well.
CREATE TABLE #SupplementalData1
(
ROWID int IDENTITY(1, 1),
LOB varchar(100),
Program varchar(100),
Project varchar(100),
Container varchar(255),
RPTNG_Week date,
Scheduled_Open int,
Still_Open int,
Scheduled_Closed int,
Actual_Closed int
);
CREATE INDEX t1
ON #SupplementalData1 (LOB, Program, Project, Container, RPTNG_Week);
INSERT INTO #SupplementalData1 (LOB, Program, Project, Container, RPTNG_Week)
SELECT DISTINCT
a.LOB_CODE,
a.PRGRM_NAME,
a.PRJCT_NAME,
a.CNTNR_NAME,
b.Monday
FROM
#data a,
Schedule_Date_Lookup b
WHERE
b.Monday >= #MinMonday
AND b.Monday <= #MaxMonday
ORDER BY
a.LOB_CODE,
a.PRGRM_NAME,
a.PRJCT_NAME,
b.Monday;
DELETE FROM #SupplementalData1
WHERE RPTNG_Week > #EndDate;
-- Get the number of rows in the looping table
DECLARE #RowCount int;
SET #RowCount = (SELECT COUNT(ROWID)FROM #SupplementalData1);
-- Declare an iterator
DECLARE #I int;
-- Initialize the iterator
SET #I = 1;
--Declare Common Variables
DECLARE #iLOB varchar(MAX),
#iProgram varchar(MAX),
#iProject varchar(MAX),
#iContainer varchar(MAX),
#iRPTNG_Week date,
#Value int;
-- Loop through the rows of a table #myTable
WHILE (#I <= #RowCount)
BEGIN
-- Declare variables to hold the data which we get after looping each record
-- Get the data from table and set to variables
SELECT #iLOB = LOB,
#iProgram = Program,
#iProject = Project,
#iContainer = Container,
#iRPTNG_Week = RPTNG_Week
FROM #SupplementalData1
WHERE ROWID = #I;
SET #Value = (SELECT COUNT(CNTNR_NAME) AS Scheduled_Open_Sum
FROM #data c
WHERE (c.NEED_DATE >= #iRPTNG_Week)
AND c.LOB_CODE = #iLOB
AND c.PRGRM_NAME = #iProgram
AND c.PRJCT_NAME = #iProject
AND c.CNTNR_NAME = #iContainer);
UPDATE #SupplementalData1
SET Scheduled_Open = #Value
WHERE LOB = #iLOB
AND Program = #iProgram
AND Project = #iProject
AND Container = #iContainer
AND RPTNG_Week = #iRPTNG_Week;
-- -- Increment the iterator
SET #I = #I + 1;
END;
Is there an alternative way that would improve speed?
Without sample data, desired output and your logic the following wasn't tested, but should get you moving in the right direction.
Do away with the entire while statement and go with a set based approach.
Here is the while loop rewritten as a SELECT. I will usually do that first to double check and validate data.
SELECT *
FROM [#SupplementalData1] [supdata]
CROSS APPLY (
SELECT COUNT([CNTNR_NAME]) AS [Scheduled_Open_Sum]
FROM [#data] [c]
WHERE [c].[NEED_DATE] >= [supdata].[RPTNG_Week]
AND [c].[LOB_CODE] = [supdata].[LOB]
AND [c].[PRGRM_NAME] = [supdata].[Program]
AND [c].[PRJCT_NAME] = [supdata].[Project]
AND [c].[CNTNR_NAME] = [supdata].[Container]
) AS [cd];
Then once you have validated that is correct you can easily rewrite that has an update. Which would be what replaces your while loop.
UPDATE [supdata]
SET [Scheduled_Open] = [cd].[Scheduled_Open_Sum]
FROM [#SupplementalData1] [supdata]
CROSS APPLY (
SELECT COUNT([CNTNR_NAME]) AS [Scheduled_Open_Sum]
FROM [#data] [c]
WHERE [c].[NEED_DATE] >= [supdata].[RPTNG_Week]
AND [c].[LOB_CODE] = [supdata].[LOB]
AND [c].[PRGRM_NAME] = [supdata].[Program]
AND [c].[PRJCT_NAME] = [supdata].[Project]
AND [c].[CNTNR_NAME] = [supdata].[Container]
) AS [cd];
I have the below pseudo code written that I want to implement in T-SQL. I need this code included in an existing stored procedure, I was trying to achieve the below with function call passing in a temp table as a parameter, is it possible to pass a temp table as a function parameter. Please let me know if there is a better approach to this.
Table: #Temp_Table has a column RefId which refers to #TempReadUpdateValue.Id. There are rules to identify if the #TempReadUpdateValue.Id can be applied to #Temp_Table.RefId.
Rule 1: the data qualifies in the DateRange
Rule 2: the #TempReadUpdateValue.Id is available if (Allowed - Used) > 0.
Allowed is fixed value and used will increment as its assigned.
I want to achieve the above with an UPDATE statement on Temp_Table, the challenge that I face is #Temp_Table.RefId = #TempReadUpdateValue.Id, need to increment
#TempReadUpdateValue.Used = #TempReadUpdateValue.Used + #Temp_Table.Units
every next row in #Temp_Table need to re-evaluate rules #1 and #2 for RefId assignment.
Update statement:
DECLARE #OLD INT = 0; -- THIS CAN ALSO BE SET TO 1, basically passed in as param to the stored procedure.
CREATE TABLE #TempReadUpdateValue
(
Id INT,
From_Date DateTime,
Thru_Date DateTime,
Allowed int,
Used int
)
CREATE TABLE #Temp_Table
(
Pk_ID INT,
DOS DateTime,
Units Int,
Ref_Id int
)
UPDATE #Temp_Table
SET Ref_Id = CASE
WHEN #OLD = 0 THEN 121
ELSE NewImplementation(DOS, Units, #TempReadUpdateValue)
END
CREATE OR ALTER FUNCTION NewImplementation
(#DOS DATETIME, #Units INT, #TempReadUpdateValue)
RETURNS INT
AS
BEGIN
DECLARE #Id INT
DECLARE #Allowed INT
DECLARE #Used INT
SELECT
#Id = Id,
#Allowed = Allowed,
#Used = Used
FROM
#TempReadUpdateValue
DECLARE #ReturnValue INT = 0
IF (#Id > 0) AND (#Allowed - #Used ) > 0
BEGIN
#ReturnValue = #Id;
UPDATE #TempReadUpdateValue
SET Used = (Used + #Units);
END
RETURN #ReturnValue
END
I have created my stored procedure, but I am confused how to set one column of from my table.
This is separate of my code:
CREATE PROC [dbo].[SP_Gabungan]
#REPORT_DT DATE
AS
BEGIN
DECLARE #action NVARCHAR(10),
#insCount INT = (SELECT COUNT (*) FROM INSERTED),
#delCount INT = (SELECT COUNT (*) FROM DELETED)
SELECT
#REPORT_DT AS REPORT_DATE,
FD.BRANCH_CODE AS [BRANCH],
#action AS [ID_OPERATIONAL], -- I want to set this value as 1(if there is a new input data, 2
-- (if there is updated data), 3 (if there is deleted data) from
-- from another field
BR.REGULATOR_BRANCH as [RG_BRANCH]
FROM
[DBO].[F_RR_FUNN] FD
LEFT JOIN
[DBO].[MS_BRANCH] BR ON BR.BRANCH_CD = FD.BRANCH_CODE
WHERE
FD.GROUP_PRODUCT = 'CA'
AND Y17sa = '1'
AND FD.REPORT_DATE = #REPORT_DT
END
How do I set column ID_OPERASIONAL as 1 (if there is a new data from another field), 2 for exists updated data from another field, 3 for deleted data from another field in a stored procedure.
ERROR from this code is:
Invalid object name 'INSERTED'
The problem the ERROR shows is that you cannot use deleted/inserted tables in stored procedures but just accessible in triggers.
If you want to have the count of inserted records or deleted records in a table there are two ways for doing this which the easiest one is:
Create you stored procedure like this:
CREATE PROC [dbo].[SP_Gabungan]
#REPORT_DT DATE,#DeletedCount INT , #InsertedCount Int
AS
BEGIN
...
Create a Trigger after insert and delete (so you can have inserted/deleted tables)
Then get the count just like you did in your code:
DECLARE #action nvarchar (10),
#insCount int = (SELECT COUNT (*) FROM INSERTED),
#delCount int = (SELECT COUNT (*) FROM DELETED)
Call your stored procedure in the Trigger and pass the #insCount and #delCount as inputs
EXEC [dbo].[SP_Gabungan]
#REPORT_DT = GETDATE() , #InsertedCount = #insCount , #DeletedCount = #delCount
A similar question is this for more other ways like temp tables or...
How use inserted\deleted table in stored procedure?
Also the link below is a question asking defining a trigger for both delete and insert so you can use both deleted/inserted tables together
SQL Trigger on Update, Insert, Delete on non-specific row, column, or table
Second way which is better when you are doing all these process a lot, is to get the log of your inserts or updates or deletes so you dont use triggers which reduce performance of your process.
(If usefull I can recommend some ideas for saving table logs)
CREATE PROC [dbo].[SP_Gabungan]
#REPORT_DT DATE
,#DeletedCount INT
,#InsertedCount INT
,#UpdateCount INT
AS BEGIN
DECLARE #action INT
SET #action = CASE
WHEN #InsertCount <> 0 THEN 1
WHEN #UpdateCount <> 0 THEN 2
WHEN #DeletedCount <> 0 THEN 3
END
SELECT
#REPORT_DT AS REPORT_DATE,
FD.BRANCH_CODE AS [BRANCH],
#action AS [ID_OPERATIONAL],
BR.REGULATOR_BRANCH as [RG_BRANCH]
FROM
[DBO].[F_RR_FUNN] FD
LEFT JOIN
[DBO].[MS_BRANCH] BR ON BR.BRANCH_CD = FD.BRANCH_CODE
WHERE
FD.GROUP_PRODUCT = 'CA'
AND Y17sa = '1'
AND FD.REPORT_DATE = #REPORT_DT END
CREATE TRIGGER [YourTriggerName]
AFTER INSERT/UPDATE/DELETE ON [db].[tablename]
FOR EACH ROW
BEGIN
DECLARE
#insCount int = (SELECT COUNT (*) FROM New), -- New in MySQL is same as inserted,deleted,updated
#delCount int = (SELECT COUNT (*) FROM Old),
#upCount int = (SELECT COUNT (*) FROM New),
EXEC [dbo].[SP_Gabungan]
#REPORT_DT = GETDATE()
,#DeletedCount = #delCount
,#InsertedCount = #insCount
,#UpdateCount = #upCount
END
I have table called sample with columns:
Id, Name, Dept, active
Query:
select Id
from Sample
where Dept = #Dept and active = 1
I want to fetch id from sample table name by passing deptment name whose is active. There can come situation where where I get 2 records. Two dept might be active. That's why I am taking top 1. Some time might not come any record.
That's why I used like this in stored procedure:
declare #TempId int
set top 1 #TempId = Id
from Sample
where Dept = #Dept and active = 1
if(#TempId is null)
begin
#TempId = 0
end
Can I use isnull in the above select instead of after which is suitable for both my conditions?
No. First it must be select, not set.
And if select returns no rows, #TempId will not be changed. See this simple example
declare #TempId int = 0;
select #TempId = null where 1=2;
select #TempId;
I would write following code:
DECLARE #TempId int =
COALESCE((SELECT TOP 1 Id FROM [Sample] WHERE Dept = #dept AND Active=1), 0)
If no rows are returned, NULL coalescing function is used.
At the time of selecting record, check for the NULL value, and select the record which is NOT NULL.
declare #TempId int
select top 1 #TempId = Id from Sample where Dept = #Dept and active = 1 and Id is not null
I want to do a if-else condition statement in SQL Server but am not sure how.
Inside the stored procedure I have the following parameters:
#MarketId nvarchar (10),
#RegionId nvarchar (10)
And the following statement:
select * from Interaction I
where
(#MarketId = 0 ) OR (I.MarketId = (SELECT Id FROM Market WHERE ExternalId = #MarketId))
What I want to do is to check the value of #MarketId
if #MarketId = 0
then I want the where condition for I.MarketId to get its Ids from elsewhere like
(SELECT ID FROM Market WHERE ExternalId = #RegionId)
otherwise, if its 1, then I just want to leave it as is and get the Id from #MarketId instead of #RegionId..
How should I go about this?
Thanks!
This should work:
SELECT *
FROM Interaction I
WHERE ( #MarketID = 0
AND EXISTS (SELECT 1 FROM Market
WHERE ExternalId = #RegionId AND Id = I.MarketID)
OR I.MarketID = #MarketID