I would like to know what the reasoning could be for inconsistent way sql server handles type overflowing. And what would be the proper way to prevent the silent data corruption SQL Server inflicts on us.
The well behaved int
An int f开发者_运维知识库or example gives a proper overflow exception
declare @b int = 123456789000
Msg 8115, Level 16, State 2, Line 3 Arithmetic overflow error converting expression to data type int.
The Silent bit
A bit value will be zero for zero and one for everything else you try to put in (with a little extra fun on an empty string).
declare @a bit = 123
, @b bit = ''
select a = @a, b = @b
output:
a b ----- ----- 1 0
create table #bit_type(a bit)
insert into #bit_type values (123), ('')
select * from #bit_type
output:
a - 1 0
declare @bit_type table (a bit)
insert into @bit_type values (123), ('')
select * from @bit_type
output:
a - 1 0
This behavior is often the cause of very hard to debug ETL problems (invalid value in an input file is silently converted to a 1 or a zero)
The schizophrenic varchar
Varchar (and char
/nchar
/nvarchar
) is another highly annoying datatype
declare @c varchar(5)
select @c = '123456789'
print @c
The result is silently truncated.
12345
create table #varchar_type(a varchar(5))
insert into #varchar_type values ('123456789')
Here we get a proper overflow error.
Msg 8152, Level 16, State 14, Line 1 String or binary data would be truncated. The statement has been terminated.
declare @varchar_type table(a varchar(5))
insert into @varchar_type values ('123456789')
Here we get a proper overflow error as well.
Msg 8152, Level 16, State 14, Line 2 String or binary data would be truncated. The statement has been terminated.
BIT
SQL is assuming that ANY numeric value is 'TRUE'
, while an empty string or 0 is 'FALSE'
.
The best way to handle this is through filtering in your code, i.e.:
DECLARE @b BIT
DECLARE @v char(4) = '1234'
SET @b = (CASE WHEN @v = '1' THEN 1 ELSE 0 END)
SELECT @b
Varchar
SQL doesn't consider @variables
as mission-critical as tables. The overflow error on tables can be disabled as well by using the SET ANSI WARNINGS OFF
command.
I think the designers also assumed that if you are declaring a variable with a length, you will handle checking the length of that variable yourself. Other reasons could include:
- You are setting the length of the variable (it's not automatic for the most part)
- You are specifying the input
- Ergo, you should know if your input will possibly overflow, and you will check for it if necessary
This is different for a string than an int since a string can still be useful when truncated, while truncation fundamentally changes the nature and value of a number.
The recommended procedure is similar to that for bit:
DECLARE @v varchar(10)
DECLARE @str varchar(25) = 'This is a longer string'
IF LEN(@str) <= 10
SET @v = @Str
ELSE RAISERROR('Invalid string length!', 0, 1) WITH NOWAIT
精彩评论