SQL update numeric column from decimal datatype - sql

I am trying to update a column of type numeric(5,2) from decimal(10,2) but the column is remaining null and I have no error messages.
DECLARE #newDurationAsDec decimal(10,2)
DECLARE #newDurationAsNum numeric(5,2)
--#newDurationAsDec is set by some logic from another table and holds the correct value e.g 2.00
set #newDurationAsNum = CAST(#newDurationAsDec AS numeric(5,2))
--selecting #newDurationAsNum contains the correct value e.g. 2.00
UPDATE table
SET Duration = #newDurationAsNum
WHERE ID = #ID AND
Duration IS NULL AND
OtherColumn = 'T'
No errors are retruned and the column is not updated. Changing the update to a select returns the correct row. can someone point out my mistake?
Thanks in advance.

Works fine for me below. Check there are no triggers that might be interfering with things.
If you are on at least SQL Server 2005 you can use the OUTPUT clause to see the row(s) updated as illustrated below.
CREATE TABLE #T
(
ID INT PRIMARY KEY,
Duration NUMERIC(5,2),
OtherColumn CHAR(1)
)
INSERT INTO #T VALUES (1,NULL,'T')
DECLARE #ID INT = 1
DECLARE #newDurationAsDec DECIMAL(10,2) = 2
DECLARE #newDurationAsNum NUMERIC(5,2)
SET #newDurationAsNum = CAST(#newDurationAsDec AS NUMERIC(5,2))
SELECT #newDurationAsNum
UPDATE #T
SET Duration = #newDurationAsNum
OUTPUT inserted.*, deleted.*
WHERE ID = #ID AND
Duration IS NULL AND
OtherColumn = 'T'
SELECT * FROM #T
DROP TABLE #T

Run a select to see what you will be updating. I embed my updates statements as shown below so it is easy to move back and forth from the select to the update just by commenting and uncommenting lines of code
--UPDATE t
--SET Duration = #newDurationAsNum
Select *, #newDurationAsNum
FROM table t
WHERE ID = #ID AND
Duration IS NULL AND
OtherColumn = 'T'

Related

Update statement, update value is conditionally evaluated

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

How can I solve my performance issue in my stored procedure?

How can I get better performance with my sql query in a SP? It has a lot of memory usage.if you look at below my execution pan you will see that :
IF NOT EXISTS(SELECT * FROM Common.[CustomerxxxIds] WHERE xyzType = #xyzType AND CustomerId = #CustomerId)[/code]
has alot of memory usage. How can I reduce that?
ALTER PROCEDURE [Common].[SaveCustomerxxxIds]
(
#xyzType NVARCHAR(128),
#CustomerId INT,
#xxxId INT OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS(SELECT * FROM Common.[CustomerxxxIds] WHERE xxxType = #xxxType AND CustomerId = #CustomerId)
BEGIN
INSERT INTO Common.[CustomerxxxIds]
([xxxId]
,[CustomerId]
,[xxxType])
VALUES
(0
,#CustomerId
,#xxxType)
END
UPDATE Common.[CustomerxxxIds]
SET [xxxId] = ([xxxId]) + 1
WHERE [xxxType] = #xxxType
AND CustomerId = #CustomerId
SELECT #xxxId = xxxId
FROM Common.[CustomerxxxIds]
WHERE [xxxType] = #xxxType
AND CustomerId = #CustomerId
END
You can do things to avoid "re-read" of the table to get the output value.
After the INSERT
( INSERT INTO Common.[CustomerxxxIds])
Use SCOPE_IDxxx() to get the newly created surrogate key.
The above will only work for IDxxx columns. From your question, you may not actually have an IDxxx column.
See
https://learn.microsoft.com/en-us/sql/t-sql/functions/scope-idxxx-transact-sql?view=sql-server-2017
.........
with the UPDATE and/or INSERT, you could use OUTPUT functionality to get the value.
https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql?view=sql-server-2017
This AVOIDS the last select statement (the "re-read" as I am calling it) to get the desired output value.
Obviously completely removing a SELECT statement will improve performance.
..
Below is a simple but complete Northwind database example of using OUTPUT for INSERT and UPDATE
SELECT 'Before' as Looksie, [ShipperID]
,[CompanyName]
,[Phone]
FROM [Northwind].[dbo].[Shippers]
--
DECLARE #MyInsertAuditTable table( AuditShipperID INT,
AuditCompanyName nvarchar(40),
AuditPhone nvarchar(24));
INSERT [Northwind].[dbo].[Shippers] (CompanyName , Phone )
OUTPUT INSERTED.ShipperID, INSERTED.CompanyName, INSERTED.Phone
INTO #MyInsertAuditTable (AuditShipperID, AuditCompanyName , AuditPhone )
SELECT TOP 1
--(SELECT MAX(ShipperID) + 1 from dbo.Shippers )
'Shipper' + LEFT(CONVERT(VARCHAR(38), NEWID()), 12)
, '(555) 555-5555'
FROM sys.objects
--Display the result set of the table variable.
SELECT AuditShipperID, AuditCompanyName, AuditPhone FROM #MyInsertAuditTable;
DECLARE #MyUpdateAuditTable table( AuditShipperID INT,
AuditCompanyName nvarchar(40),
AuditOldPhone nvarchar(24),
AuditNewPhone nvarchar(24));
UPDATE [Northwind].[dbo].[Shippers]
SET Phone = '(777) 555-7777'
OUTPUT inserted.ShipperID, inserted.CompanyName ,
deleted.Phone,
inserted.Phone
INTO #MyUpdateAuditTable ( AuditShipperID, AuditCompanyName, AuditOldPhone , AuditNewPhone)
FROM [Northwind].[dbo].[Shippers] shippers
JOIN #MyInsertAuditTable insAudit on shippers.ShipperID = insAudit.AuditShipperID
SELECT * from #MyUpdateAuditTable
SELECT 'After' as Looksie, [ShipperID]
,[CompanyName]
,[Phone]
FROM [Northwind].[dbo].[Shippers]
--
Results
Looksie ShipperID CompanyName Phone
Before 1 Speedy Express (503) 555-9831
Before 2 United Package (503) 555-3199
Before 3 Federal Shipping (503) 555-9931
..
AuditShipperID AuditCompanyName AuditPhone
9 Shipper3C062D46-EEA (555) 555-5555
...
AuditShipperID AuditCompanyName AuditOldPhone AuditNewPhone
9 Shipper3C062D46-EEA (555) 555-5555 (777) 555-7777
..
Looksie ShipperID CompanyName Phone
After 1 Speedy Express (503) 555-9831
After 2 United Package (503) 555-3199
After 3 Federal Shipping (503) 555-9931
After 9 Shipper3C062D46-EEA (777) 555-7777
You can achieve this by changing SELECT * to SELECT 1. it might help
IF NOT EXISTS (SELECT 1 FROM Common.[CustomerxxxIds]
WHERE xyzType = #xyzType AND CustomerId = #CustomerId)
Try this
ALTER PROCEDURE [Common].[SaveCustomerxxxIds]
(
#xyz NVARCHAR(128),
#CustomerId INT,
#xxxId INT OUTPUT
)
AS
BEGIN
set #xxxId=null
--Get xxxId
SELECT #xxxId=[xxxId] FROM Common.[CustomerxxxIds] WHERE xyz = #xyz AND CustomerId = #CustomerId
--If #xxxId means no record we should insert
if (#xxxId is null)
begin
--When insert we always insert xxxId as 0 then update to one then we collect the value (one) from db and return it.
--Better set value directly as one insert it to DB and return it as one. Instead of insert, update, select
--just insert
set #xxxId = 1
INSERT INTO Common.[CustomerxxxIds]
([xxxId]
,[CustomerId]
,[xyz])
VALUES
(#xxxId
,#CustomerId
,#xyz)
end
else
begin
--If we have the value we add one to it update the record and return it.
--better than update table then select.
--We already have the value we add one to it then update table and return the value we have
set #xxxId+=1
UPDATE Common.[CustomerxxxIds] SET [xxxId] = #xxxId
WHERE [xyz] = #xyz AND CustomerId = #CustomerId
END
end

SQL While Loop Insert with values from another table

I am trying to create a SQL While loop that will update a temp table with values from another table. Values from the other table:
477286
560565
499330
391827
127375
526354
501736
357359
410433
500946
261297
377667
135931
235691
247239
143672
548752
471945
...
Wrote the following, however, it only inserts the last value multiple times over.
Here is the code:
USE Reports
GO
CREATE TABLE #TempTable (CreatedByID int, LastUpdatedByID int, ID int,
AlertDE int, Alert char(50), StartDTTM datetime, EndDTTM datetime,
IsInactiveFLAG char(1),AlertDetails char(1));
DECLARE #numrows INT
SELECT #numrows = COUNT(*) FROM [Reports].[dbo].[Eligible]
DECLARE #id int
DECLARE #LoopCount INT = 1
DECLARE #count int = #numrows
SELECT #id = [id] FROM [Reports].[dbo].[Eligible]
WHILE (#LoopCount <= #count)
BEGIN
INSERT INTO #TempTable (CreatedByID, LastUpdatedByID, ID, AlertDE, Alert, StartDTTM, EndDTTM, IsInactiveFLAG,AlertDetails)
VALUES (52,52,#id,0,'Eligible',CURRENT_TIMESTAMP,'1900-01-01
00:00:00.000','N','')
SET #LoopCount = #LoopCount + 1
END
SELECT * FROM #TempTable
DROP TABLE #TempTable
I am assuming I have to tell it to loop through the values in the other table somehow but I am not positive if that is the right approach or if in general I am taking the long way around the bus.
Why are you using a loop? You can do this with an insert . . . select statement:
INSERT INTO #TempTable (CreatedByID, LastUpdatedByID, ID, AlertDE, Alert, StartDTTM, EndDTTM, IsInactiveFLAG, AlertDetails)
SELECT 52, 52, e.id, 0, 'Eligible', CURRENT_TIMESTAMP, '1900-01-01 00:00:00.000', 'N', ''
FROM [Reports].[dbo].[Eligible] e ;
See eg https://www.w3schools.com/sql/sql_insert_into_select.asp for more info.
GMR, I found a way to accomplish my need which is similar to yours. Hopefully this will help you too.
DECLARE
#LoopId int
,#TheOrderNumber varchar(20)
DECLARE #CheckThisItem TABLE
(
LoopId int not null identity(1,1)
,TheOrderNumber varchar(20) not null
)
INSERT #CheckThisItem
SELECT Order_Number AS TheOrderNumber
FROM [dbo].[Table_Storing_Order_Number] ORDER BY Order_Number ASC
SET #LoopId = ##rowcount
WHILE #LoopId > 0
BEGIN
SELECT #TheOrderNumber = TheOrderNumber
FROM #CheckThisItem
WHERE LoopId = #LoopId
-- Start inserting record pulled for while loop
INSERT [dbo].[The_Destination_Table]
SELECT TOP (1)
A, B, C, D
FROM [dbo].[Source_Table] ST
WHERE
ST.Order_Number = #TheOrderNumber
-- Set number to reduce loop counter
SET #LoopId = #LoopId - 1
END;

Finding MAX value of data type Varchar

Firstly I have a table tblSample with ID as column of datatype INT. To auto generate ID for every transaction, I created a stored procedure:
DECLARE #Id INT
SELECT #Id = MAX(Id)
FROM tblSample
IF #Id IS NULL
BEGIN
SELECT 0 as Id
END
ELSE
SELECT MAX(Id) as ID FROM tblSample
Here as you observe if ID has no rows MAX(Id)=0 then return 0 or else return MAX(ID) value so that next insertion will be greater than max(ID).
That's fine but now I had column ID with datatype VARCHAR I have to do similar operation how can I that?
The code looks fine so it should work with VARCHAR also but my suggestion is to use storage variable also with same datatype so it won't get conflicted anywhere in the operation:
DECLARE #Id VARCHAR(10)
I think you could use MAX(CAST(varcharcolumn AS Int))
DECLARE #Id INT
SELECT #Id=MAX(Id) FROM tblSample
IF #Id IS NULL
BEGIN
SELECT 'Your_VarCharValue' + CAST(0 AS VARCHAR) as Id
END
ELSE
SELECT 'Your_VarCharValue' + CAST(MAX(Id) AS VARCHAR) as ID FROM tblSample

SQL - Getting Updated Value

I use Sql Server 2008.
I have a table that generates ID.
I want to retrieve the generated ID and store it in a bigint variable.
How can I do it?
Here is the Stored Proc that gives the ID as result set. But I cannot store it in a bigint variable.
ALTER PROC SCN.TRANSACTION_UNIQUE_ID_SELECT
AS
UPDATE COR.TRANSACTION_UNIQUE_ID
SET ID = ID + 1
OUTPUT INSERTED.ID AS ID
If you want to use output you can;
declare #ID table (ID bigint)
update the_table
set ID = ID + 1
output INSERTED.ID into #ID
declare #bi bigint = (select ID from #ID)
The BigInt should be an identity insert column, this will make SQL Server automatically generate bigints in sequence for you. Just pass the rowID as an OUTPUT parameter and set it before the procedure ends after the insert/update.
Then you can read it coming back and set it as needed.
The stored procedure could look something like this (I've only included the rowID for clarity):
CREATE PROCEDURE [Sample].[Save]
(
#rowID bigint OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
--Do your insert/update here
--Set the RowID
SET #rowID = (SELECT SCOPE_IDENTITY())
END
That UPDATE looks fishy...it will increment every ID in your table by one, no?
Anyway, variables have an #sign, so just SET #myvar = ...whatever...
Use OUTPUT INTO:
DECLARE #TblID TABLE ( ID int )
UPDATE COR.TRANSACTION_UNIQUE_ID
SET ID = ID + 1
OUTPUT INSERTED.ID INTO #TblID (ID) --the output values will be inserted
--into #TblID table-variable
DECLARE #id BIGINT
EXEC #id = SCN.TRANSACTION_UNIQUE_ID_SELECT