MySQL converting to TINYINT - mysql

Under what circumstances will MySQL convert types to TINYINT? I know that a BOOL or BOOLEAN type in mysql DDL will automatically be converted to TINYINT(1) for for true or false. I am analyzing a database which has a type of varchar(16) on a field in one table, and tinyint(4) on the same field on another table? E.g t1.name varchar(15) and t2.name tinyint(4) where t1.name=t2.name.

Don't rely on implicit type conversion, do your datatype analysis manually:
First lets see what MySQL thinks as the best col-type for your data. Run a
SELECT * FROM table PROCEDURE Analyse()
Analyse your data further by saying
SELECT * FROM table WHERE varcharCol NOT REGEXP '^[0-9].*$'
To get all non-numeric values in varcharCol. If there are non you finally have to check value-ranges of different MySQL-types here.
Then you are ready to convert your varcharCol e.g. to TINYINT.

Related

UUID as default for MySQL id column

I am trying to add a column to an existing table in MySql 8.0.17. The column needs to contain a UUID and I am trying to set it as a default value.
This is the statement I am executing
ALTER TABLE myTable ADD COLUMN UUID varchar(36) NOT NULL DEFAULT (UUID());
However I am getting the following error
Error Code: 1674. Statement is unsafe because it uses a system function that may return a different value on the slave.
I have read from other posts that it is possible to create a Trigger on the table however i would like to find out whether it is possible to set it directly as the default value on the column.
Also, what would be the advantage of using a binary conversion of the UUID over just a simple UUID ?
Eg.
ALTER TABLE myTable ADD COLUMN UUID binary(16) NOT NULL DEFAULT (UUID_TO_BIN(UUID(), true));
Thanks for your help.
assigning UUID() as DEFAULT value won't work, because It does not guarantee that the same value will be generated on your replica. That is why using TRIGGER is good option for new records (insertions).
If your intention is to update current records as well, you can write an update statement
update myTable
set UUID = UUID()
your column is of type binary(16) which means UUID data is implicitly converted to binary. using UUID_TO_BIN is not needed.
EDIT:
CHAR/VARCHAR is the human-readable format. whereas, binary is the compact format.
That means compressing the 32 characters (36 or more with separators) to the 16-bit format or back to the human-readable format.
If you dont mind about reading UUID, best is to use binary format
Change VARCHAR to CHAR, this will let you use 16bit.
Old Method
ALTER TABLE myTable ADD COLUMN UUID varchar(36) NOT NULL DEFAULT (UUID());
New Method
ALTER TABLE myTable ADD COLUMN UUID BINARY(36) NOT NULL DEFAULT (UUID_TO_BIN(UUID()));

Why mysql query is slow without quotation mark?

The table DDL as flows:
CREATE TABLE `video` (
`short_id` varchar(50) NOT NULL,
`prob` float DEFAULT NULL,
`star_id` varchar(50) NOT NULL,
`qipu_id` int(11) NOT NULL,
`cloud_url` varchar(100) DEFAULT NULL,
`is_identical` tinyint(1) DEFAULT NULL,
`quality` varchar(1) DEFAULT NULL,
PRIMARY KEY (`short_id`),
KEY `ix_video_short_id` (`short_id`),
KEY `sid` (`star_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
The video table has 4.5 million lines.
I execute the same query in mysql shell client as flows. except in where clause the star_id equal to a value with quatation mark, another not as flows.
select * from video where star_id="215343405";
12914 rows in set (0.22 sec)
select * from video where star_id=215343405;
12914 rows in set (3.17 sec)
the one with quatation mark is 10x faster then another(I have create index on star_id).i watch out the slow one does not use the index. I just wonder how mysql process the query?
mysql> explain select * from video where star_id=215343405;
Thanks advance!
This is answered in the manual:
For comparisons of a string column with a number, MySQL cannot use an
index on the column to look up the value quickly. If str_col is an
indexed string column, the index cannot be used when performing the
lookup in the following statement:
SELECT * FROM tbl_name WHERE str_col=1;
The reason for this is that there are many different strings that may convert to the value 1, such as '1', ' 1', or '1a'.
If you do not use Quotation marks mysql uses the value as an int and must convert the value for every record. Therefor the db needs a lot of time.
The quotes define the expression as a string, whereas without the single quote it is evaluated as a number. This means that MySQL is forced to perform a Type Conversion to convert the number to a CHAR to do a proper comparison.
As the doc above says,
For comparisons of a string column with a number, MySQL cannot use an
index on the column to look up the value quickly. If str_col is an
indexed string column, the index cannot be used when performing the
lookup...
However, the inverse of that is not true and while the index can be used, using a string as a value causes a poor execution plan (as illustrated by jkavalik's sqlfiddle) where using where is used instead of the faster using index condition. The main difference between the two is that the former requires a row lookup and the latter can get the data directly from the index.
You should definitely modify the column data type (assuming it truly is only meant to contain numbers) to the appropriate data type ASAP, but make sure that no queries are actually using single quotes, otherwise you'll be back where you started.

Converting SQL Server code to MySQL

I am trying to concatenate two integers as the default value in a third field. My create table in SQL Server works fine:
CREATE TABLE MEI_Tbl
(
MEI_ID int PRIMARY KEY IDENTITY (1,1),
SRC tinyint NOT NULL DEFAULT '2',
HEI_ID AS (Cast (SRC as varchar)+ Cast (MEI_ID as varchar))
);
but when I try to create it in MySQL, I cannot find the equivalent for the concatenation of the two integers (Line 5 HEI_ID...).
**
I am aware of changing IDENTITY (1,1) to AUTO_INCREMENT for MySQL.
**
I have also tried several concat methods, but to no avail.
MySQL seems happier if I define the datatype for HEI_ID, and I have done so as varchar and int but again no success.
I have spent too much time reading about tool kits to convert SQL Server to MySQL. I just want to create the table in MySQL.
Any input would be appreciated.
MySQL does not support computed columns. Instead, you can use a view:
CREATE TABLE MEI_Tbl (
MEI_ID int PRIMARY KEY AUTO_INCREMENT,
SRC tinyint NOT NULL DEFAULT 2
);
CREATE VIEW v_MEI_Tbl as
SELECT MEI_ID, SRC,
CONCAT(src, mei_d) as HEI_ID
FROM MEI_Tbl
);
Then query from the view.

What is the correct way to write a query that matches on a UUID column in MySQL?

I have an application which I am porting from Postgres to MySQL. Nevermind why. The application uses Entity Framework 4 to query the database.
For various reasons, I have to use Guids in my C# code, save them to the database, and then query data based on the saved values of the Guids. I'm not very familiar with MySQL & how it handles what are essentially blobs.
First, there is no UUID type in MySQL. I have to save them as BINARY(16) values. OK, fine. I have created the columns as BINARY(16) and the data is written into the table. Good.
My problem is that I can't see to match on the stored values of the Guids. I have written a unit test that writes data with a known Guid to the table then tries to retrieve it. The data is going into the database fine but when I try to read it back, I get no rows.
Here's a sample table schema:
CREATE TABLE `MyDatabase`.`MyTable` (
`id` INT NOT NULL AUTO_INCREMENT,
`guid` BINARY(16) NOT NULL,
`applicationId` INT(11) NOT NULL,
`name` VARCHAR(256) NOT NULL,
Description VARCHAR(256) NULL,
SessionTimeout INT NOT NULL,
DomainId INT NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT IX_aspnetx_groups UNIQUE ( `applicationId`, `id` )
);
Here's the Entity Framework code:
var g = ( from r in context.MyTable
where r.guid = id
select r ).Single();
Here's the query that's generated by Entity Framework:
SELECT
`Extent1`.`id`,
`Extent1`.`guid`,
`Extent1`.`applicationId`,
`Extent1`.`name`,
`Extent1`.`Description`,
`Extent1`.`SessionTimeout`,
`Extent1`.`DomainId`
FROM `aspnetx_groups` AS `Extent1`
WHERE `Extent1`.`guid` = '81d7de5e-4212-4ff8-b3d4-9f115261971d' LIMIT 2;
When this executes, it returns no rows, resulting in a "sequence contains no elements" exception being thrown in my C# code.
How do I make this work?
In the WHERE clause on your SELECT, it looks like you are comparing a BINARY(16) (guid on the left side of the equals) with a character string literal on the right side.
To perform a valid comparison, I would convert that character string literal into a BINARY(16), and then compare that to guid.
So, removing all the dash characters and then using the UNHEX function should do the trick:
WHERE `Extent1`.`guid` =
UNHEX(REPLACE('81d7de5e-4212-4ff8-b3d4-9f115261971d','-',''))
For performance, you'll want your query to reference the bare guid column on the left side (just like it does), and not wrap the guid column in any sort of functions. You'll want any conversion to be done on the literal side of the predicate, so that the conversion only has to be done once at the beginning of the query, rather than having to do a conversion for each row in the table.
It turns out that the problem I was having had to do with quirks of the Entity Framework connector in the MySQL Connector/Net package. There is a connection string setting that you need to add if you are using BINARY(16) as the data type of your Guids in the database:
Old Guids=True
Once you add that to the connection string, Entity Framework starts to emit code that really works when inserting, updating, or comparing Guids.
I've also come to the conclusion that UUID / Guid support in MySQL is only half-baked and needs some serious work to bring it up to a usable state.

What is the default value for a field if no default value is provided?

I hope this isn't a dumb question. You can set a default value for all variables or a function for when it is inserted. but if the field is not required to insert and you don't allow null values, what is the "blank" value that you see in phpMyAdmin? in a query is it returned as empty string, etc?
just trying to figure it out, I want to query for all records such that the value for a specific column in that record is not "empty" or blank or whatever.
thanks.
Referring to the manual,
For data entry for a NOT NULL column that has no explicit DEFAULT
clause, if an INSERT or REPLACE statement includes no value for the
column, or an UPDATE statement sets the column to NULL, MySQL handles
the column according to the SQL mode in effect at the time:
If strict SQL mode is not enabled, MySQL sets the column to the implicit default value for the column data type.
If strict mode is enabled, an error occurs for transactional tables and the statement is rolled back. For nontransactional tables, an
error occurs, but if this happens for the second or subsequent row of
a multiple-row statement, the preceding rows will have been inserted.
So your question now may be, what are the implicit default values for the various column data types? Here you go:
Implicit defaults are defined as follows:
For numeric types, the default is 0, with the exception that for integer or floating-point types declared with the AUTO_INCREMENT
attribute, the default is the next value in the sequence.
For date and time types other than TIMESTAMP, the default is the appropriate “zero” value for the type. For the first TIMESTAMP column
in a table, the default value is the current date and time. See Section 10.3, “Date and Time Types”.
For string types other than ENUM, the default value is the empty string. For ENUM, the default is the first enumeration value.
There IS no default value unless you specify one (i.e. unless you define a "default constraint" for the column in question).
Here's an example for adding a default on an existing column:
ALTER TABLE dbo.customer ALTER COLUMN contactname SET DEFAULT 'Unknown'
Here's an example creating the table with a default:
CREATE TABLE Books (
ID SMALLINT NOT NULL,
Name VARCHAR(40) NOT NULL,
PubID SMALLINT NOT NULL DEFAULT 0
)
It's good practice to declare ALL columns "not null", and provide default constraints as appropriate.
In the "books" example above, if you "insert" without specifying PubID, the PubID will be zero.
In the same example, if you "insert" without specifying ID or Name ... you'll get an error.
If you want MySQL to auto-assign an ID, use this syntax instead:
CREATE TABLE Books (
ID SMALLINT NOT NULL AUTO_INCREMENT,
Name VARCHAR(40) NOT NULL,
PubID SMALLINT NOT NULL DEFAULT 0
)
If you want to disallow null :-
alter table YOUR_TABLE modify column COLUMN varchar(255) not null default '';
The above query will disallow null and assign an empty string when the value is not supplied.
In phpmysqladmin, blank = empty.
Via PHP mysqli function or mysql function, null value is returned as null still.
Once you have apply the query, you can easily filter that by using
select ... from YOUR_TABLE
where COLUMN != ""; <-- no need to check is null
<-- because the first query already enforce not null
However, is best for you do this before perform the alter :-
update YOUR_TABLE set COLUMN = ""
where COLUMN is null;