SQL Server hexadecimal handling - sql-server

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

Related

Conversion failed when converting the varchar value 'SAT' to data type int

I have a table ConsoleGames wherein all columns are of type varchar(50). When I try to create a new table console_games by amending existing datatypes by using the query:
CREATE TABLE console_games
(
game_rank integer,
game_name varchar(1200),
platform_name varchar(1200),
game_year integer,
genre varchar(200),
publisher varchar(1200),
na_sales float,
eu_sales float,
jp_sales float,
other_sales float
)
INSERT INTO console_games
SELECT *
FROM [dbo].[RAWConsoleGames]
I get the following error message:
Msg 245, Level 16, State 1, Line 17
Conversion failed when converting the varchar value 'SAT' to data type int.
When I look into the data in the table the value 'SAT' is in a column for which I am not changing the datatype. 'SAT' value exists in the Platform column which is of varchar type and I am not trying to change the type to int.
Any help will be appreciated.
Thanks
Clearly 'SAT' is not and will never convert to an INT.
Always best to specify the columns to insert ... things change
Now, if the source data is suspect, add a try_convert(). If the conversion fails, a null value will be returned
I don't know the column names of your source, so I substituted SomeColN
INSERT INTO console_games
SELECT try_convert(integer ,SomeCol1)
,try_convert(varchar(1200),SomeCol2)
,try_convert(varchar(1200),SomeCol3)
,try_convert(integer ,SomeCol4)
,try_convert(varchar(200) ,SomeCol5)
,try_convert(varchar(1200),SomeCol6)
,try_convert(float ,SomeCol7)
,try_convert(float ,SomeCol8)
,try_convert(float ,SomeCol9)
,try_convert(float ,SomeCol10)
FROM [dbo].[RAWConsoleGames]
Just for fun, try:
Select try_convert(int,'SAT')
Select try_convert(int,'25.25')
Select try_convert(int,'25')
You should always define the list of columns you're inserting into, and you should also always define the list of columns you're selecting from. Furthermore, I'd recommend to explicitly do any type conversions instead of leaving that up to SQL Server - if you do it yourself, you know when and what you're doing.
So I'd write that statement like this:
-- **DEFINE** the list of columns you're inserting into
INSERT INTO console_games (rank, name, Platform, year, genre, publisher,
sales, eu_sales, jp_sales, other_sales)
-- **DEFINE** the list of columns you're selecting, and any conversions
SELECT
game_rank, game_name, platform_name,
CAST(game_year AS VARCHAR(50)), genre,
publisher,
CAST(na_sales AS VARCHAR(50)),
CAST(eu_sales AS VARCHAR(50)),
CAST(jp_sales AS VARCHAR(50)),
CAST(other_sales AS VARCHAR(50))
FROM
[dbo].[RAWConsoleGames]

TSQL issue when updating value and outputing inserted value into log table

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

t-sql view conversion failed when filtering on converted column

I am trying to create view by filtering some table, and include some converted to different type column into select list. View filter excludes from result set rows in which this column can not be converted to that type. Then I select rows from this view and filter rows using this converted column. And I always get error Conversion failed when converting the nvarchar value '2aaa' to data type int
SQL Fiddle
MS SQL Server 2008 Schema Setup:
create table _tmp_aaa (id int identity(1, 1), value nvarchar(max) not null)
go
insert _tmp_aaa (value) values ('1111'), ('11'), ('2aaa')
go
create view _tmp_v_aaa
as
select id, cast(value as int) as value from _tmp_aaa where value like '1%'
go
Query 1:
select * from _tmp_v_aaa where value = 11
Are there any workarounds?
Add to your view ISNUMERIC to check if string is numeric value:
CREATE VIEW _tmp_v_aaa
AS
SELECT
id,
[value] = CAST((CASE WHEN ISNUMERIC([value]) = 1 THEN [value] ELSE NULL END) AS INT)
FROM _tmp_aaa
WHERE [value] LIKE '1%'
AND ISNUMERIC([value]) = 1
I tried some tricks... Obviously the optimizer tries to hand down your where criterium where it is not yet tranformed. This is one problem to be solved with a. multi-statement function. Their biggest disadvantage is the advantage in this case: the optimizer will not look into it, but just take their result "as is":
create function fn_tmp_v_aaa()
returns #tbl table(id INT, value INT)
as
BEGIN
INSERT INTO #tbl
select id, cast(value as int) as value from _tmp_aaa where value like '1%'
RETURN;
END
select * from dbo.fn_tmp_v_aaa() where value=11;
If you look at the execution plan , predicates are passed down to the table something like....
And your query gets translated to something like .....
select id, cast(value as int) as value
from tmp_aaa
where CONVERT(INT, value,0) like '1%'
AND CONVERT(INT, value,0) = CONVERT(INT, 11,0)
Now if you run this query you will get the same error you get when you query against the view.
Conversion failed when converting the nvarchar value '2aaa' to data type int.
When the predicate CONVERT(INT, value,0) like '1%' is converted , you have INT on one side of the expressions and varchar on another, INT being the higher precedence, sql server tries to convert whole expression to INT and fails hence the error message.

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.

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.

Resources