How restrict mysql tiny-int to accept just integer - mysql

Im trying to get eeror about invalid data for a query but it seems mysql accept strings as tiney in queries and set 0 instead of returning any error.
So how can I restrict it to just accept integers.
Thanks in advance.

This is SQL Mode-dependent.
In strict mode you must receive either 'Data truncated' (inserted value starts from numeric chars) or 'Incorrect integer value' (first symbol is not numeric) error message, and none data must be inserted.
If strict mode is disabled then warning is generated instead of error, and the value is converted to numeric (all symbols starting from first non-numeric one are truncated, then the value is converted to number, if it is empty string then zero is assigned).
Data type checking (and convertion if needed) is performed firstly, even before BEFORE INSERT trigger.
DEMO

Related

Mysql enum field problems

in a mysql table I have a field of type Enum ('S', 'N') with default value = S. Now I have checked this table and I find many records that have no value in this field. How is it possible? I wanted to force the values of this field to be only S and N. Where did I go wrong?
Mysql version 5.0.92
my field definition:
`conteggia` enum('S','N') NOT NULL default 'S'
From the Empty or NULL Enumeration Values documentation:
If you insert an invalid value into an ENUM (that is, a string not present in the list of permitted values), the empty string is inserted instead as a special error value. ...
If strict SQL mode is enabled, attempts to insert invalid ENUM values result in an error.
So you must not have strict mode enabled, and due to some error in your code it assigned invalid values to the column.

Why does a query return a result if the field is numeric and the WHERE clause is a string?

I am running a query on a db table which is returning one record when I expect it to return no records.
SELECT yeargroupID FROM tbl_yeargroup WHERE yeargroup='S' AND schoolID=2.
The yeargroup field is a tinyint field. Thefore the WHERE clause is looking the letter 'S' in the numeric field, so should not find anything. Yet it returns the record with the yeargroup = 0, and yeargroupID=17 (the bottom record in the table)
I'm confused as to why it is returning this record and how to avoid it.
Thanks
This logic, as you have pointed out, is comparing a number and a string:
WHERE yeargroup = 'S'
Handling such situations is an important part of most SQL compilers, and it is well documented. The solution is to implicitly convert values to "conforming" types. This is sad. My preference would be for the compiler to generate an error and force the user to use correct types. I find that implicit conversion creates more problems than it solves.
In any case, the rules in this case are pretty simple. The string is converted to an integer. But, how is a string with no digits converted? Well, the rule in MySQL is that the leading digits are converted to a number. And if there are none, the value is 0. So, this turns into:
where yeargroup = 0
You can see the results more clearly if you run:
select 'S', 'S' + 0
Note that most databases would return an error in this case (a type conversion error). But even those would accept the string if it looked like a number, so this would be allowed:
where yeargroup = '5'
What is the proper solution? Never mix types. Do not construct queries by munging constant values. Instead, queries from an application should always be using parameters.

Select statement returns data although given value in the where clause is false

I have a table on my MySQL db named membertable. The table consists of two fields which are memberid and membername. The memberid field has the type of integer and uses auto_increment function starting from 2001. The membername table has the type of varchar.
The membertable has two records with the same order as described above. The records look like this :
memberid : 2001
membername : john smith
memberid : 2002
membername : will smith
I found something weird when I ran a SELECT statement against the memberid field. Running the following statement :
SELECT * FROM `membertable` WHERE `memberid` = '2001somecharacter'
It returned the first data.
Why did that happen? There's no record with memberid = 2001somecharacter. It looks like MySQL only search the first 4 character (2001) and when It's found related data, which is the returned data above, it denies the remaining characters.
How could this happen? And is there any way to turn off this behavior?
--
membertable uses innodb engine
This happens because mysql tries to convert "2001somecharacter" into a number which returns 2001.
Since you're comparing a number to a string, you should use
SELECT * FROM `membertable` WHERE CONVERT(`memberid`,CHAR) = '2001somecharacter';
to avoid this behavior.
OR to do it properly, is NOT put your search variable in quotes so that it has to be a number otherwise it'll blow up because of syntax error and then in front end making sure it's a number before passing in the query.
sqlfiddle
Your finding is an expexted MySQL behaviour.
MySQL converts a varchar to an integer starting from the beginning. As long as there are numeric characters wich can easily be converted, they are icluded in the conversion process. If there's a letter, the conversion stops returning the integer value of the numeric string read so far...
Here's some description of this behavior on the MySQL documentation Site. Unfortunately, it's not mentioned directly in the text, but there's an example which exactly shows this behaviour.
MySQL is very liberal in converting string values to numeric values when evaluated in numeric context.
As a demonstration, adding 0 causes the string to evaluated in a numeric context:
SELECT '2001foo' + 0 --> 2001
, '01.2-3E' + 0 --> 1.2
, 'abc567g' + 0 --> 0
When a string is evaluated in a numeric context, MySQL reads the string character by character, until it encounters a character where the string can no longer be interpreted as a numeric value, or until it reaches the end of the string.
I don't know of a way to "turn off" or disable this behavior. (There may be a setting of sql_mode that changes this behavior, but likely that change will impact other SQL statements that are working, which may stop working if that change is made.
Typically, this kind of check of the arguments is done in the application.
But if you need to do this in the SELECT statement, one option would be cast/convert the column as a character string, and then do the comparison.
But that can have some significant performance consequences. If we do a cast or convert (or any function) on a column that's in a condition in the WHERE clause, MySQL will not be able to use a range scan operation on a suitable index. We're forcing MySQL to perform the cast/convert operation on every row in the table, and compare the result to the literal.
So, that's not the best pattern.
If I needed to perform a check like that within the SQL statement, I would do something like this:
WHERE t.memberid = '2001foo' + 0
AND CAST('2001foo' + 0 AS CHAR) = '2001foo'
The first line is doing the same thing as the current query. And that can take advantage of a suitable index.
The second condition is converting the same value to a numeric, then casting that back to character, and then comparing the result to the original. With the values shown here, it will evaluate to FALSE, and the query will not return any rows.
This will also not return a row if the string value has a leading space, ' 2001'. The second condition is going to evaluate as FALSE.
When comparing an INT to a 'string', the string is converted to a number.
Converting a string to a number takes as many of the leading characters as it can and still be a number. So '2001character' is treated as the number 2001.
If you want non-numeric characters in member_id, make it VARCHAR.
If you want only numeric ids, then reject '200.1character'

how to convert values from database to be numeric?

I'm grabbing all the values of a column using:
> myValues <- dbGetQuery(mydb,"select average_Medicare_allowed_amt from STAGING_MEDICAREPUF")
because the values are defined as varchar, when I do a summary(myValues) r is not recognizing that the values are numerical:
Assuming I have no access to the backend schema, and am unable to cast the varchars to decimals, is it possible to first convert myValues to be numerical and then get a summary?
In MySQL, I find that the easiest way to convert to a number value is to simply add zero:
select (average_Medicare_allowed_amt + 0) as average_Medicare_allowed_amt
Note that the use of the column alias. This allows you to refer to the resulting value using the same name.
MySQL does "silent" conversion. If it encounters an error or a non-numeric character, then the conversion stops. So, 'abc' + 0 returns 0 instead of generating an error.
And, regarding your comment, I have never heard of "cast()" permissions in any database.

MySQL Enum's always contain '' (empty string) in possibilities

I'm trying to create a simple 'yes'/'maybe'/'no' Enum in MySQL with PhpMyAdmin
I set NULL to No, and 'maybe' as the default value
I am expecting an error when executing something like "SET EnumCol=''", because '' (an empty string) should not be a valid value.
But the query gets executed and the value gets set to '' - which means I'm forced to double check for this unwanted and illegal value whenever I read from the database!
Is this a bug in MySQL or PhpMyAdmin?
Does anyone know a way of disabling this behavior?
Thanks.
Empty string is error indicator of invalid values in ENUM. From mysql ENUM type manual:
If you insert an invalid value into an ENUM (that is, a string not present in the list of allowed values), the empty string is inserted instead as a special error value. This string can be distinguished from a “normal” empty string by the fact that this string has the numerical value 0. More about this later.
To disable this behaviour:
If strict SQL mode is enabled, attempts to insert invalid ENUM values result in an error.
To enable strict mode see Server SQL Modes.
ENUM's are a pain in the butt. unless you also need to set the value by a number, i would stay away from them.
instead, use a varchar column with a foreign key to a lookup table to restrict the values. that will make it impossible to insert a bad value.