Is This Odd Behavior? Empty String ('') vs int

  • I found this out by chance today while trying to figure out the strange results of some T-SQL code on a couple of our servers.

    CREATE TABLE test1

    (

    id int,

    [name] varchar(20)

    )

    INSERT INTO test1(id,[name]) VALUES (1,'Mike')

    INSERT INTO test1(id,[name]) VALUES (2,'Jeff')

    INSERT INTO test1(id,[name]) VALUES ('','WhoamI')

    INSERT INTO test1(id,[name]) VALUES (0,'Correct0')

    SELECT * FROM test1

    SELECT * FROM test1 WHERE id = 0;

    SELECT * FROM test1 WHERE id = '';

    SELECT * FROM test1 WHERE id = '0';

    Now, the results of this are different from what I'd expect. I would have guessed that the 'whoamI' record would be rejected during insert for not being 'numeric' (Note: SELECT IsNumeric('') returns a 0...), and that the WHERE id = '' CLAUSE would break for similar reasons. This is not the case.

    Thing is, here's where it really threw me:

    TRUNCATE TABLE test1;

    ALTER TABLE test1 ADD CONSTRAINT ck_id CHECK (id <> '')

    GO

    INSERT INTO test1(id,[name]) VALUES (1,'Mike')

    INSERT INTO test1(id,[name]) VALUES (2,'Jeff')

    INSERT INTO test1(id,[name]) VALUES ('','WhoamI')

    INSERT INTO test1(id,[name]) VALUES (0,'Correct0')

    SELECT * FROM test1

    SELECT * FROM test1 WHERE id = 0;

    SELECT * FROM test1 WHERE id = '';

    SELECT * FROM test1 WHERE id = '0';

    DROP TABLE test1

    The last two records are not inserted. This (kinda sorta) implies " '' = '0' ", which is where my brain shuts down :-). Now, I'm sure there's a simple explanation for why this happens, but since I've never encountered the situation before I was hoping some of you guys might be able to explain what I'm missing here. Is there another way to look at this so the current behavior would make more sense to me?

    Thanks in advance!

    Regards,

    Mike M

  • Empty strings = 0. It's kind of arbitrary, but that's how it works.

    IsNumeric has a number of flaws, this is just one of them. Check out IsNumeric('1d3') for a surprising result. It's valid, because it's an extended numeric shorthand. At the same time, Cast('1d3' as Int) will fail, but casting it to Float will succeed and give you 1000. Those are some of the reasons I don't trust IsNumeric. It does what it's supposed to, but what it's designed to do isn't helpful to me in any of the situations that I need it for.

    On the last bit, casting '0' to an integer is an allowed implicit conversion, so that's why that is succeeding. Implicit conversions can be tricky at first, but once you get the hang of them, they're pretty obvious.

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • i thought it was one of those implicit conversion things;

    when your WHERE is evaluated here:

    id = '';

    the id column is implicitly converted to varchar....since every int can convert to a varchar, there's no problem;

    how that '' gets converted to zero...i dunno;

    It's not the opposite, where the '' is converted to a number; there is an order of implicit conversions, and i've seen it somewhere, but won't stick my foot in my mouth guessing which goes to what.

    Lowell


    --help us help you! If you post a question, make sure you include a CREATE TABLE... statement and INSERT INTO... statement into that table to give the volunteers here representative data. with your description of the problem, we can provide a tested, verifiable solution to your question! asking the question the right way gets you a tested answer the fastest way possible!

  • GSquared (4/12/2010)


    Empty strings = 0. It's kind of arbitrary, but that's how it works..

    That's what I was hoping wouldn't be the answer, but was expecting it anyway. 😉

    IsNumeric has a number of flaws, this is just one of them.

    I've seen you guys rip into it in the past. Jeff M recently posted a list in another forum that made me chuckle.

    On the last bit, casting '0' to an integer is an allowed implicit conversion, so that's why that is succeeding. Implicit conversions can be tricky at first, but once you get the hang of them, they're pretty obvious.

    Yeah, *normally* I'm good on implicit conversions. This ('' = 0) and ('' = '0') thing was completely new to me. I've never seen it in 10 years of SQL coding. I put the above test together to confirm that I wasn't crazy.

    Thanks for the input!

    Regards,

    Mike M

  • GSquared (4/12/2010)


    Empty strings = 0. It's kind of arbitrary, but that's how it works.

    IsNumeric has a number of flaws, this is just one of them. Check out IsNumeric('1d3') for a surprising result. It's valid, because it's an extended numeric shorthand. At the same time, Cast('1d3' as Int) will fail, but casting it to Float will succeed and give you 1000. Those are some of the reasons I don't trust IsNumeric. It does what it's supposed to, but what it's designed to do isn't helpful to me in any of the situations that I need it for.

    On the last bit, casting '0' to an integer is an allowed implicit conversion, so that's why that is succeeding. Implicit conversions can be tricky at first, but once you get the hang of them, they're pretty obvious.

    Actually, none of that is a "flaw" per se`. IsNumeric handles those just like it's supposed to. Since the value (a form of engineering notation, in the case of '1d3') can be successfully converted to a "numeric" value using some method, it will dutifully report a "1" for such values just like it'll report a "1" for the following...

    SELECT ISNUMERIC('1,1,1,1,1,1,1.1'),

    ISNUMERIC(CHAR(9)+'1')

    The problem is that people mistake the term "IsNumeric" for "IsAllDigits" and the two just aren't the same. 🙂 From Books Online...

    ISNUMERIC returns 1 when the input expression evaluates to a valid integer, floating point number, money or decimal type; otherwise it returns 0. [font="Arial Black"]A return value of 1 indicates that expression can be converted to at least one of the numeric types[/font].

    No where does it make the qualification of being an "IsAllDigits" function. It will take anything that can be converted to a number using one method or another including signage, a couple of forms of engineering notation, currency marks, currency characters, tabs, spaces, CrLf's, hard spaces, and a whole bunch more and report it as a "1".

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.
    "Change is inevitable... change for the better is not".

    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)
    Intro to Tally Tables and Functions

  • Jeff: I understand that IsNumeric does what it's designed to do, but I still consider it "flawed" because it has almost no practical use in my experience. That's why I specifically stated, "It does what it's supposed to, but what it's designed to do isn't helpful to me in any of the situations that I need it for." It's not buggy, but it is, in my opinion, flawed.

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

Viewing 6 posts - 1 through 5 (of 5 total)

You must be logged in to reply to this topic. Login to reply