TSQL issue when updating value and outputing inserted value into log table - sql-server

I update a ClientFunds.Balance table column with a value and use the Ouput Inserted.Balance clause to write the value to a log table.
Occasionally the value written to the ClientFunds table is truncated whilst the value written to the log table is always correct.
First, I fill this table with the details of what will be updated on the ClientFunds table:
declare #ToUpdate table
(
Id int identity(1,1),
ClientFundId int,
Total decimal (18, 2),
Rate decimal (10, 5)
);
This table will hold the data to be written to the log table:
declare #Updated as table
(
ClientFundId int,
AmountBefore decimal (18,2),
AmountAfter decimal (18,2),
ToUpdateId int
);
Here's how I update the ClientFunds table, using the #ToUpdate table and ouput the log information to the #Updated table. I've snipped a few details of the loop here but you should get the idea:
WHILE ##FETCH_STATUS = 0
BEGIN
update cf
set cf.Balance = cf.Balance - (up.Total * up.Rate)
OUTPUT INSERTED.Id, DELETED.Balance, INSERTED.Balance, up.Id
INTO #Updated
from #ToUpdate up
join dbo.ClientFunds cf on cf.Id = up.ClientFundId
where up.Id = #CurrentId
FETCH NEXT FROM ToUpdate_Cursor into #CurrentId;
END
Now, as I said, occasionally the dbo.ClientFunds.Balance value, which is decimal (18, 2), will be written to the db with the decimal part truncated yet the inserted value output to #ToUpdate retains the correct value.
For instance, one example is 14454.36 being written to the #Updated table, and ultimately the log file, but 14454.00 being written to dbo.ClientFunds.Balance.
Any idea of what could be happening?
Thanks,
Jules

Related

How to add decimal to numbers stored as text?

I have some currency values stored in a table in a varchar(50) column. Unfortunately I cannot alter the data being imported, and the values are stored without decimal points. I need to get the values from the varchar column in a format where I can divide them by 100 to add the decimal. It would be awesome if I could just update the column to add the decimal.
I've tried CONVERTing and CASTing, yet when I divide by 100 it appears to simply truncate the two rightmost digits instead of actually performing the division.
Ultimately I just need the decimal points added to this column and am totally baffled.
Any help would be most appreciated!!
Thanks in advance!
Is this what you want:
declare #Currency as varchar(50)
set #Currency = 8000;
declare #CurrencyDecimal as decimal(18,2)
set #CurrencyDecimal = #Currency /100
select cast(#CurrencyDecimal as varchar(50))
and/or this:
select cast(#Currency / 100 as decimal(18,2) )
select convert(DECIMAL(18,2),#Currency / 100)
if you need to update:
update t1
set Currency = cast(Currency as decimal(18,2) )
where = -- some condition
Data Types (Transact-SQL)
CAST and CONVERT
I think you can use the STUFF function to respond to this request :
"It would be awesome if I could just update the column to add the decimal."
UPDATE [table] SET [column] = STUFF([column],LEN([column])-1,0,'.')

Computed column value not the same as Scalar Function it uses

I have a Table with a computed column that uses a scalar function
CREATE FUNCTION [dbo].[ConvertToMillimetres]
(
#fromUnitOfMeasure int,
#value decimal(18,4)
)
RETURNS decimal(18,2)
WITH SCHEMABINDING
AS
BEGIN
RETURN
CASE
WHEN #fromUnitOfMeasure=1 THEN #value
WHEN #fromUnitOfMeasure=2 THEN #value * 100
WHEN #fromUnitOfMeasure=3 THEN #value * 1000
WHEN #fromUnitOfMeasure=4 THEN #value * 25.4
ELSE #value
END
END
GO
The table has this column
[LengthInMm] AS (CONVERT([decimal](18,2),[dbo].[ConvertToMillimetres]([LengthUnitOfMeasure],[Length]))) PERSISTED,
Assuming that the [Length] on the Table is 62.01249 and [LengthUnitOfMeasure] is 4 the LengthInMm computed value comes with 1575.11 but when i run the function directly like
SELECT [dbo].[ConvertToMillimetres] (4, 62.01249) GO
It comes with 1575.12
[Length] column is (decimal(18,4, null))
Can anyone tell why this happens?
I'm not sure this really counts as an answer, but you've perhaps got a problem with a specific version of SQL?
I just had a go at replicating it (on a local SQL 2014 install) and got the following:
create table dbo.Widgets (
Name varchar(20),
Length decimal(18,4),
LengthInMm AS [dbo].[ConvertToMillimetres] (4, Length) PERSISTED
)
insert into dbo.Widgets (Name, Length) values ('Thingy', 62.01249)
select * from dbo.Widgets
Which gives the result:
Name Length LengthInMm
-------------------- --------------------------------------- ---------------------------------------
Thingy 62.0125 1575.12
(1 row(s) affected)
Note that your definition uses [LengthInMm] AS (CONVERT([decimal](18,2),[dbo].[ConvertToMillimetres]([LengthUnitOfMeasure],[Length]))) PERSISTED, but that doesn't seem to make a difference to the result.
I also tried on my PC (Microsoft SQL Server 2012 - 11.0.2100.60 (X64)). Works fine:
CREATE TABLE dbo.data(
LengthUnitOfMeasure INT,
[Length] decimal(18,4),
[LengthInMm] AS (CONVERT([decimal](18,2),[dbo].[ConvertToMillimetres]([LengthUnitOfMeasure],[Length]))) PERSISTED
)
INSERT INTO dbo.data (LengthUnitOfMeasure, [Length])
SELECT 4, 62.01249
SELECT *
FROM dbo.data
/*
RESULT
LengthUnitOfMeasure Length LengthInMm
4 62.0125 1575.12
*/
I think, I found the answer:
Lets see what you are saying:
There is a column with decimal(18,4) data type.
There is a calculated column which depend on this column.
The result differs when you select the calculated field and when you provide the same result manually. (Right?)
Sorry, but the input parameters are not the same:
The column in the table is decimal(18,4). The value you are provided manually is decimal(7,5) (62.01249)
Since the column in the table can not store any values with scale of 5, the provided values will not be equal. (Furthermore there is no record in the table with the value of 62.01249 in the Length column)
What is the output when you query the [Length] column from the table? Is it 62.0124? If yes, then this is the answer. The results can not be equal since the input values are not equal.
To be a bit more specific: 62.01249 will be casted (implicit cast) to 62.0125.
ROUND(25.4 * 62.0124, 2) = 1575.11
ROUND(25.4 * 62.0125, 2) = 1575.12
EDIT Everybody who tried to rebuild the schema made the same mistake (Including me). When we (blindly) inserted the values from the original question into our instances, we inserted the 62.01249 into the Length column -> the same implicit cast occured, so we have the value 62.0125 in our tables.

Error converting data type varchar to numeric. SQL Server

I'm writing data on the Sql Server database.
When data is written, a trigger runs.
TRIGGER
ALTER TRIGGER Alert ON records AFTER INSERT AS
BEGIN
DECLARE #tempmin decimal = 0
DECLARE #current_max_idAlarm int = (SELECT MAX(IdAlarm) FROM alarms)
DECLARE #maxidAlarm int
DECLARE #temp decimal = (SELECT s.lim_inf_temp from sensores s JOIN inserted i ON s.idSensor=i.idSensor )
-- Insert into alares from the inserted rows if temperature less than tempmin
SET IDENTITY_INSERT alarmes On
INSERT alarmes (IdAlarm, desc_alarm,date, idRecord)
SELECT
ROW_NUMBER() OVER (ORDER BY i.idRecord) + #current_max_idAlarm, 'Temp Error', GETDATE(), i.idRecord
FROM
inserted AS i
WHERE
i.Temperature < #temp
end
INSERT
insert into record values ('2014-05-26' ,'14:51:47','Sensor01','---','48.6','9.8');
Whenever I try to record this type of data: '---'
Gives the following error:
Msg 8114, Level 16, State 5, Procedure Alert, Line
Error converting data type varchar to numeric.
I know it is to be in decimal type (DECLARE #temp decimal - TRIGGER), but moving to the type varchar to trigger stops working correctly.
Does someone can help me resolve this error please?
Thank you all.
You are trying to insert --- inside a numeric column, you simply can't do that.
You have mainly 2 options:
Change the data type of the destination column
Choose a different value to insert (like NULL)

Timeout because of temp table

In my stored procedure I'm using #temptable to fetch the data from one table and updating that #temptable for result. In my production environment this stored procedure is consuming a lot of time which is causing timeouts at times but in lower environment this query works absolute perfect.
CREATE TABLE #TempTable
(
ID int IDENTITY PRIMARY KEY,
TOTALPOLICY nvarchar(14),
SYMBOL nvarchar (3),
POLNUM nvarchar (7),
MODULE nvarchar (2),
LOC char (2),
MCO char (2),
LOB char (3),
INSUREDNAME nvarchar (100),
TotalPremium decimal (10,2),
ServiceCharges decimal (10,2),
TotalPaid decimal (10,2),
TotalRefunded decimal (10,2),
CurrentBalance decimal (10,2),
TotalBilled decimal (10,2),
PCO char (2)
)
INSERT INTO #TempTable (TOTALPOLICY,SYMBOL, POLNUM, MODULE, LOC, MCO, LOB, INSUREDNAME,TotalPremium, ServiceCharges, TotalPaid, TotalRefunded, CurrentBalance, TotalBilled, PCO) --PCR 109 SMT added PCO
EXEC(#sql)
--PCR 109 Start SMT
Update #TempTable
Set TotalPaid = IsNull((Select sum(PaymentAmt)
From SHCashActivity with (nolock)
Where #TempTable.POLNUM = PolicyNbr
and #TempTable.Module = PolicyModuleNbr
and #TempTable.Symbol = PolicySymbolCd
and CashActivityTypeCd in ('P', 'C', 'N')
and CashAppliedStatusCd in ('1','2')), 0)
Please advise me what could be solution for this .
The problem is not the temp table. The problem is the process takes too long. Re-architect your process so an answer is generated in a more acceptable length of time.
Also, your update statement is hard to read. It is also vulnerable to breaking if a field is added to SHCashActivity/#TempTable that matches the name of a field in the other table. Create table alias-es and use them for all field access.
Also,
create index X on #TempTable (POLNUM, Module, Symbol)
will help. The correct order of the fields in the index will depend upon indexes on SHCashActivity.

SQL Server hexadecimal handling

I believe I'm having a problem with the way SQL Server 2000 handles hexadecimal numbers.
If I do a
select * from table where [timestamp] = 44731446
the row that it returns shows the timestamp as 0x0000000202AA8C36
Equally in another table if I
select * from table2 where [timestamp] = 44731446
the row that it returns shows the timestamp as 0x0000000002AA8C36 (notice the missing 2)
MS Calc tells me that the first timestamp = 8634666038 in decimal and the second timestamp = 44731446 in decimal which matches my original query on both tables.
So why is SQL Server returning a different number, yet successfully querying it? I believe this is the route of an update problem I'm having where the row won't update.
Long story short, the binary to integer conversion is truncating data:
select cast(0x0000000202AA8C36 as int)
A TIMESTAMP column is really BINARY(8), so your query is comparing a BINARY(8) value to an INT value; because INT has the higher precedence, MSSQL converts the BINARY(8) value to INT before comparing them.
But, 0x0000000202AA8C36 (or 8634666038) is too big to be represented as INT, so MSSQL has to truncate it first, and it truncates to the same value as 0x0000000002AA8C36. This might be a little clearer:
create table dbo.t (tstamp binary(8) not null)
go
insert into dbo.t values (0x0000000202AA8C36)
insert into dbo.t values (0x0000000002AA8C36)
go
-- returns 2 rows
select * from dbo.t where tstamp = 44731446
-- returns 1 row
select * from dbo.t where tstamp = cast(44731446 as bigint)
go
drop table dbo.t
go
According to Books Online (for 2008, I don't have 2000):
When [non-string data types] are converted to
binary or varbinary, the data is
padded or truncated on the left.
Padding is achieved by using
hexadecimal zeros

Resources