Optimise Stored Procedure Update and Select - sql

The stored procedure I've created works, but is there a more efficient way of doing this? To be fair there is no performance hit for any of this nor does it need optimised but I'd like to know in the interest of doing things correctly.
Execution plan states query 1: 17%, query 2: 67%, query 3: 16%
DECLARE #CurrentVoucherID int;
SET #CurrentVoucherID =
(
SELECT TOP(1) IdGiftVoucherPhysicalCode
from GiftVoucherPhysicalCodes
WHERE Activated = 0 and assigned = 0 and Value = 10
ORDER BY IdGiftVoucherPhysicalCode
);
UPDATE GiftVoucherPhysicalCodes
SET Activated = 1, Activated_at = GETDATE()
WHERE IdGiftVoucherPhysicalCode = #CurrentVoucherID;
SELECT * FROM GiftVoucherPhysicalCodes
WHERE IdGiftVoucherPhysicalCode = #CurrentVoucherID;

I may not be understanding it correctly, but it looks like you are just running the update one record at a time? Why not do it in bulk?
UPDATE GiftVoucherPhysicalCodes
SET Activated = 1, Activated_at = GETDATE()
WHERE Activated = 0 and assigned = 0 and Value = 10

you can do it without variable
UPDATE GiftVoucherPhysicalCodes
SET Activated = 1, Activated_at = GETDATE()
WHERE IdGiftVoucherPhysicalCode = (SELECT TOP(1) IdGiftVoucherPhysicalCode
from GiftVoucherPhysicalCodes
WHERE Activated = 0 and assigned = 0 and Value = 10
ORDER BY IdGiftVoucherPhysicalCode)
SELECT * FROM GiftVoucherPhysicalCodes
WHERE IdGiftVoucherPhysicalCode = (SELECT TOP(1) IdGiftVoucherPhysicalCode
from GiftVoucherPhysicalCodes
WHERE Activated = 1 and assigned = 0 and Value = 10
ORDER BY IdGiftVoucherPhysicalCode)

Related

Faster way to update multiple columns for 10's of thousands of rows

I have a process that I built, I work for a company with multiple brands (children companies).
For each of these brands the process finds all placed orders and builds a POST request to a 3rd party that provides a specific customer experience. To do this I store all placed orders into a table. each brand gets their own table. The table looks like this essential
| **ID - PKey(1,1)** | **Order#** | **#OfItemsOrdered** | **#OfItemsShipped** | **#OfItemsCancelled** |
The process will check each warehouse system we have which are basically sql tables that indicate whether the order was shipped.
Once it checks an order it will determine if there was any changes since the last time it ran and return a SQL update string.
Once all the orders are checked it will generate a file into a folder with the update scripts like below.
There are typically 85-100k lines
UPDATE [].[CORP\].[tbl_Narvar_OrderLog_21] SET ItemsShipped = 1, LastUpdateDate = GETDATE(), IsReady = 1 where NarvarID = 7132532;
UPDATE [].[CORP\].[tbl_Narvar_OrderLog_21] SET ItemsShipped = 2, LastUpdateDate = GETDATE(), IsReady = 1 where = 7132533;
UPDATE [].[CORP\].[tbl_Narvar_OrderLog_21] SET ItemsShipped = 1, LastUpdateDate = GETDATE(), IsReady = 1 where NarvarID = 7132534;
UPDATE [].[CORP\].[tbl_Narvar_OrderLog_21] SET ItemsShipped = 10, LastUpdateDate = GETDATE(), IsReady = 1 where NarvarID = 7132536;
UPDATE [].[CORP\].[tbl_Narvar_OrderLog_21] SET ItemsShipped = 1, LastUpdateDate = GETDATE(), IsReady = 1 where NarvarID = 7132537;
I have a separate task that will check the folder and run all the scripts..
Is there any way to speed up the process or perhaps even a different method entirely that I am unaware of to update a large number of rows where each row will have different updated values?
Also simply using a transaction will vastly improve the runtime of a script with thousands of individual single-row updates. Without a transaction SQL Server has to wait for a physical IO to the log file after every row.
EG
BEGIN TRANSACTION;
UPDATE [].[CORP\].[tbl_Narvar_OrderLog_21] SET ItemsShipped = 1, LastUpdateDate = GETDATE(), IsReady = 1 where NarvarID = 7132532;
UPDATE [].[CORP\].[tbl_Narvar_OrderLog_21] SET ItemsShipped = 2, LastUpdateDate = GETDATE(), IsReady = 1 where = 7132533;
UPDATE [].[CORP\].[tbl_Narvar_OrderLog_21] SET ItemsShipped = 1, LastUpdateDate = GETDATE(), IsReady = 1 where NarvarID = 7132534;
UPDATE [].[CORP\].[tbl_Narvar_OrderLog_21] SET ItemsShipped = 10, LastUpdateDate = GETDATE(), IsReady = 1 where NarvarID = 7132536;
UPDATE [].[CORP\].[tbl_Narvar_OrderLog_21] SET ItemsShipped = 1, LastUpdateDate = GETDATE(), IsReady = 1 where NarvarID = 7132537;
COMMIT TRANSACTION;
You can put the values into a table and use a single update. As a derived table, this looks like:
UPDATE nol
SET ItemsShipped = COALESCE(v.ItemsShipped, nol.ItemsShipped),
LastUpdateDate = GETDATE(),
IsReady = COALESCE(v.IsReady, nol.IsReady)
FROM [].[CORP\].[tbl_Narvar_OrderLog_21] nol JOIN
(VALUES (7132532, 1, NULL),
(7132533, 2, 1),
. . .
) v(NarvarID, ItemsShipped, IsReady)
ON nol.NarvarID = v.NarvarID;
The VALUES clause can be replaced by an explicit table or subquery. The VALUES should have alternate values for any column that could be updated. NULL is assumed to mean "keep the current value", so COALESCE() is used in the SET.
At the very least, this eliminates the overhead of a separate query, commit, and round-trip to the database for every update.
It is imperative to think in term of sets when dealing with tables in SQL. I suggest having a temporary table or CTE to hold value NarvarID that has to be updated.
Following SQL Queries update table by inner joining it to #temp table
IF OBJECT_ID('TEMPDB..#temp','U') IS NOT NULL DROP TABLE #temp
Create Table #temp (ItemsShipped int, NarvarID int)
Insert into #temp(ItemsShipped , NarvarID)
Values (10,7132536)
,(1,7132532)
-- And List goes on
Update OL SET
OL.ItemsShipped = T.ItemsShipped,
OL.LastUpdateDate = GETDATE(),
OL.IsReady = 1
From [tbl_Narvar_OrderLog_21] OL inner join #temp T
ON OL.NarvarID = T.NarvarID

Update Zero to One and One to Zero in SQL Server

I have a table with flag 0 and 1.
Please tell me how to update Zero to One and One to Zero
DECLARE #a INT, #b INT
SELECT #a = number
FROM zerone
WHERE number = 0
SELECT #b = number
FROM zerone
WHERE number = 1
BEGIN
IF #a = 0
UPDATE zerone
SET number = 1
WHERE #a = 0
ELSE IF #b = 1
UPDATE zerone
SET number = 0
WHERE #b = 1
END
This query is not working for me.
use the below query to update 0 to 1 and 1 to 0
update zerone set number= 1-number
Just this:
UPDATE zerone
SET number = CASE WHEN number = 1 THEN 0 ELSE 1 END;
you should also always consider NULL values in update operations and must explicitly filter them out
UPDATE zerone
SET number= case
when 1 then 0
when 0 then 1
end
WHERE number in (0,1)
Also your query will not work because you are assigning a single variable with a rows of data in the select statement.
SELECT #a = number
FROM zerone
WHERE number = 0
This does not work like as you are expecting and will only assign #a with value either NULL(if there are no rows) or with 0 if there is a row. If there are multiple rows even then it will have a single value 0
As you have seen there are so many ways to perform that task but in this case, I would prefer #Abdul Rasheed.
We can also use below IIF logical function in SQLSERVER2012 or above.
UPDATE zerone
SET number = IIF (number = 1, 0, 1)

ERROR : Using EXEC and Select in Same Procedure

i have the following statements for my procedure
DECLARE #StockA table (GoodID int,NominalQty decimal(16,2),ActualQty decimal(16,2))
INSERT INTO #StockA(GoodID,NominalQty,ActualQty)
EXEC ('INV.[usp_GetStorageAvailability] ' + #SysYear +',"2015-01-01",1')
UPDATE #ReqItems
SET Stock = S.ActualQty , Rem = (S.ActualQty - R.Qty) FROM #ReqItems R JOIN #StockA S on R.GoodID = S.GoodID
DECLARE #HasMinus tinyint
SET #HasMinus = (SELECT TOP 1 * FROM #ReqItems WHERE Rem < 0)
IF #HasMinus > 0 begin
DECLARE #GC nvarchar(10)
SET #GC = (SELECT TOP 1 GoodCode FROM #ReqItems WHERE Rem < 0)
SET #Outcome = 0
SET #Descr = 'XZY'
end
SELECT #Outcome,#Descr
and i get the following error :
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
what should i do ?
thanks
The problem is here:
SET #HasMinus = (SELECT TOP 1 * FROM #ReqItems WHERE Rem < 0)
I think the error is pretty clear. The * refers to multiple columns. You need to choose one:
SET #HasMinus = (SELECT TOP 1 ?? FROM #ReqItems WHERE Rem < 0);
I'm not sure which column you want to select, however.
If you just want a count, you can do:
SELECT #HasMinus = COUNT(*) FROM #ReqItems WHERE Rem < 0;
This might be the intention of your code. (Note that the SET isn't necessary.)

SQL Server - Select max

I have a SQL Server stored procedure with an update statement:
UPDATE Sale_Sheet
SET concluded = 'True'
, concluded_time = GETDATE()
, saleNumber = (SELECT MAX(saleNumber) + 1 FROM Sale_Sheet)
WHERE vatNumber = #vatNumber
AND [user_id] = #user_id
It happens that two users initiate a procedure at the same time, and both users receive the same maximum value (SELECT MAX(saleNumber) + 1 FROM Sale_Sheet). How can I fix this?

SQL Stored Procedure set variables using SELECT

I have a stored procedure in SQL Server 2005 with multiple variables and I want to set the values of these variables using a select statement. All three variables come from a same table and there should be a way to set them using one select statement instead of the way I currently have as shown below. Please help me to figure it out.
DECLARE #currentTerm nvarchar(max)
DECLARE #termID int
DECLARE #endDate datetime
SET #currentTerm =
(
Select CurrentTerm from table1 where IsCurrent = 1
)
SET #termID =
(
Select TermID from table1 where IsCurrent = 1
)
SET #endDate =
(
Select EndDate from table1 where IsCurrent = 1
)
select #currentTerm = CurrentTerm, #termID = TermID, #endDate = EndDate
from table1
where IsCurrent = 1
One advantage your current approach does have is that it will raise an error if multiple rows are returned by the predicate. To reproduce that you can use.
SELECT #currentTerm = currentterm,
#termID = termid,
#endDate = enddate
FROM table1
WHERE iscurrent = 1
IF( ##ROWCOUNT <> 1 )
BEGIN
RAISERROR ('Unexpected number of matching rows',
16,
1)
RETURN
END