In MySQL, what is the best way of programmatically retrieving the character set and the collation of the current database?
Is the following:
SELECT
default_character_set_name, default_collation_name
FROM
information_schema.SCHEMATA
WHERE
SCHEMA_NAME = SCHEMA()
identical to the below example?
select ##character_set_database, ##collation_database
According to the documentation:
character_set_database
...
The character set used by the default
database. The server sets this variable whenever the default database
changes. If there is no default database, the variable has the same
value as character_set_server.
...
and
collation_database
...
The collation used by the default database. The
server sets this variable whenever the default database changes. If
there is no default database, the variable has the same value as
collation_server.
...
with both sentences would obtain the same result:
SELECT
default_character_set_name, default_collation_name
FROM
information_schema.SCHEMATA
WHERE
SCHEMA_NAME = SCHEMA()
and
select ##character_set_database, ##collation_database
demonstrated in the following test:
mysql> DROP DATABASE IF EXISTS `my_database`;
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT SCHEMA();
+----------+
| SCHEMA() |
+----------+
| NULL |
+----------+
1 row in set (0.00 sec)
mysql> SELECT
-> ##SESSION.character_set_database,
-> ##SESSION.collation_database,
-> ##SESSION.character_set_server,
-> ##SESSION.collation_server;
+----------------------------------+------------------------------+--------------------------------+----------------------------+
| ##SESSION.character_set_database | ##SESSION.collation_database | ##SESSION.character_set_server | ##SESSION.collation_server |
+----------------------------------+------------------------------+--------------------------------+----------------------------+
| latin1 | latin1_swedish_ci | latin1 | latin1_swedish_ci |
+----------------------------------+------------------------------+--------------------------------+----------------------------+
1 row in set (0.00 sec)
mysql> CREATE DATABASE IF NOT EXISTS `my_database`
-> CHARACTER SET utf8mb4
-> COLLATE utf8mb4_general_ci;
Query OK, 1 row affected (0.00 sec)
mysql> SELECT SCHEMA();
+----------+
| SCHEMA() |
+----------+
| NULL |
+----------+
1 row in set (0.00 sec)
mysql> SELECT
-> ##SESSION.character_set_database,
-> ##SESSION.collation_database,
-> ##SESSION.character_set_server,
-> ##SESSION.collation_server;
+----------------------------------+------------------------------+--------------------------------+----------------------------+
| ##SESSION.character_set_database | ##SESSION.collation_database | ##SESSION.character_set_server | ##SESSION.collation_server |
+----------------------------------+------------------------------+--------------------------------+----------------------------+
| latin1 | latin1_swedish_ci | latin1 | latin1_swedish_ci |
+----------------------------------+------------------------------+--------------------------------+----------------------------+
1 row in set (0.00 sec)
mysql> USE `my_database`;
Database changed
mysql> SELECT SCHEMA();
+-------------+
| SCHEMA() |
+-------------+
| my_database |
+-------------+
1 row in set (0.00 sec)
mysql> SELECT
-> ##SESSION.character_set_database,
-> ##SESSION.collation_database,
-> ##SESSION.character_set_server,
-> ##SESSION.collation_server;
+----------------------------------+------------------------------+--------------------------------+----------------------------+
| ##SESSION.character_set_database | ##SESSION.collation_database | ##SESSION.character_set_server | ##SESSION.collation_server |
+----------------------------------+------------------------------+--------------------------------+----------------------------+
| utf8mb4 | utf8mb4_general_ci | latin1 | latin1_swedish_ci |
+----------------------------------+------------------------------+--------------------------------+----------------------------+
1 row in set (0.00 sec)
mysql> SELECT
-> `DEFAULT_CHARACTER_SET_NAME`,
-> `DEFAULT_COLLATION_NAME`
-> FROM
-> `information_schema`.`SCHEMATA`
-> WHERE
-> SCHEMA_NAME = SCHEMA();
+----------------------------+------------------------+
| DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME |
+----------------------------+------------------------+
| utf8mb4 | utf8mb4_general_ci |
+----------------------------+------------------------+
1 row in set (0.00 sec)
however, a union of both sentences would not be wrong:
mysql> USE `my_database`;
Database changed
mysql> SELECT
-> `DEFAULT_CHARACTER_SET_NAME`,
-> `DEFAULT_COLLATION_NAME`
-> FROM
-> `information_schema`.`SCHEMATA`
-> WHERE
-> SCHEMA_NAME = SCHEMA() AND
-> `DEFAULT_CHARACTER_SET_NAME` = ##SESSION.character_set_database AND
-> `DEFAULT_COLLATION_NAME` = ##SESSION.collation_database;
+----------------------------+------------------------+
| DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME |
+----------------------------+------------------------+
| utf8mb4 | utf8mb4_general_ci |
+----------------------------+------------------------+
1 row in set (0.00 sec)
Related
How can I check what the current value of FOREIGN_KEY_CHECKS is?
I want to be sure that the value is 1.
Check 5.1.5 Server System Variables::foreign_key_checks:
mysql> SELECT ##GLOBAL.foreign_key_checks, ##SESSION.foreign_key_checks;
+-----------------------------+------------------------------+
| ##GLOBAL.foreign_key_checks | ##SESSION.foreign_key_checks |
+-----------------------------+------------------------------+
| 1 | 1 |
+-----------------------------+------------------------------+
1 row in set (0.01 sec)
UPDATE
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.7.18 |
+-----------+
1 row in set (0.00 sec)
mysql> SELECT IF((SELECT `VARIABLE_VALUE`
-> FROM `performance_schema`.`global_variables`
-> WHERE `VARIABLE_NAME` = 'foreign_key_checks') = 'ON', 1, 0) `global.foreign_key_checks`,
-> IF((SELECT `VARIABLE_VALUE`
-> FROM `performance_schema`.`session_variables`
-> WHERE `VARIABLE_NAME` = 'foreign_key_checks') = 'ON', 1, 0) `session.foreign_key_checks`;
+---------------------------+----------------------------+
| global.foreign_key_checks | session.foreign_key_checks |
+---------------------------+----------------------------+
| 1 | 1 |
+---------------------------+----------------------------+
1 row in set (0.00 sec)
I need to search a text field on a database avoiding mismatch for special chars but for the same phrase.
For example, if my search term in DB field is saved as "I lòve mysql ánd query" I would like to match the search for "I love mysql ánd query","I love mysql and query","I löve mysql ánd query",etc.
I was thinking to convert the phrases with a PHP function that I use for url rewrites flattening them out always to "I love mysql and query" but I'm not sure I can flatten them out in the query?
Since your data is already written to the DB with accents, can you try using DB collation to map directly between accented characters:
$connection->query("SET NAMES utf8 COLLATE utf8_general_ci");
You can read more about it here
The page above explaints clearly what this collation will do for you:
mysql> SET NAMES 'utf8' COLLATE 'utf8_general_ci';
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE t1
(c1 CHAR(1) CHARACTER SET UTF8 COLLATE utf8_general_ci);
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t1 VALUES ('a'),('A'),('À'),('á');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT c1, HEX(c1), HEX(WEIGHT_STRING(c1)) FROM t1;
+------+---------+------------------------+
| c1 | HEX(c1) | HEX(WEIGHT_STRING(c1)) |
+------+---------+------------------------+
| a | 61 | 0041 |
| A | 41 | 0041 |
| À | C380 | 0041 |
| á | C3A1 | 0041 |
+------+---------+------------------------+
4 rows in set (0.00 sec)
You can also test it for youself directly in the DB (test taken from here):
mysql> SET NAMES 'utf8' COLLATE 'utf8_general_ci';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT 'a' = 'A', 'a' = 'À', 'a' = 'á';
+-----------+-----------+-----------+
| 'a' = 'A' | 'a' = 'À' | 'a' = 'á' |
+-----------+-----------+-----------+
| 1 | 1 | 1 |
+-----------+-----------+-----------+
1 row in set (0.06 sec)
Since I need several mediumtext fields I need the barracuda file format. There are many articales and videos on how to convert an existing antelope table to barracuda but none on how to create a new table using barracuda. Is there an easy to do this with MariaDB? I'd like to use a docker container if possible.
It's messy in 5.6 (MariaDB 10.0 and 10.1):
SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_large_prefix=1; -- optional (if you also need wide indexes)
ALTER TABLE tbl ROW_FORMAT=DYNAMIC;
It's possibly defaulted correctly in 5.7 (MariaDB 10.2).
Try:
MariaDB [_]> SELECT VERSION();
+-----------------+
| VERSION() |
+-----------------+
| 10.1.23-MariaDB |
+-----------------+
1 row in set (0.00 sec)
MariaDB [_]> SHOW VARIABLES LIKE 'innodb_file_format';
+--------------------+----------+
| Variable_name | Value |
+--------------------+----------+
| innodb_file_format | Antelope |
+--------------------+----------+
1 row in set (0.01 sec)
MariaDB [_]> CREATE TABLE `barracuda_table` (`col` MEDIUMTEXT) ROW_FORMAT=DYNAMIC;
Query OK, 0 rows affected, 2 warnings (0.00 sec)
MariaDB [_]> SHOW WARNINGS;
+---------+------+--------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------------------------+
| Warning | 1478 | InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. |
| Warning | 1478 | InnoDB: assuming ROW_FORMAT=COMPACT. |
+---------+------+--------------------------------------------------------------------+
2 rows in set (0.00 sec)
MariaDB [_]> SELECT ROW_FORMAT
-> FROM `information_schema`.`tables`
-> WHERE `TABLE_SCHEMA` = DATABASE() AND
-> `TABLE_NAME` = 'barracuda_table';
+------------+
| ROW_FORMAT |
+------------+
| Compact |
+------------+
1 row in set (0.00 sec)
MariaDB [_]> DROP TABLE `barracuda_table`;
Query OK, 0 rows affected (0.00 sec)
MariaDB [_]> SET ##GLOBAL.innodb_file_format = 'Barracuda';
Query OK, 0 rows affected (0.00 sec)
MariaDB [_]> SHOW VARIABLES LIKE 'innodb_file_format';
+--------------------+-----------+
| Variable_name | Value |
+--------------------+-----------+
| innodb_file_format | Barracuda |
+--------------------+-----------+
1 row in set (0.00 sec)
MariaDB [_]> CREATE TABLE `barracuda_table` (`col` MEDIUMTEXT) ROW_FORMAT=DYNAMIC;
Query OK, 0 rows affected (0.00 sec)
MariaDB [_]> SELECT ROW_FORMAT
-> FROM `information_schema`.`tables`
-> WHERE `TABLE_SCHEMA` = DATABASE() AND
-> `TABLE_NAME` = 'barracuda_table';
+------------+
| ROW_FORMAT |
+------------+
| Dynamic |
+------------+
1 row in set (0.00 sec)
MariaDB [_]> SELECT `NAME`, `FILE_FORMAT`, `ROW_FORMAT`
-> FROM `information_schema`.`INNODB_SYS_TABLES`
-> WHERE `NAME` = '_/barracuda_table';
+-------------------+-------------+------------+
| NAME | FILE_FORMAT | ROW_FORMAT |
+-------------------+-------------+------------+
| _/barracuda_table | Barracuda | Dynamic |
+-------------------+-------------+------------+
1 row in set (0.00 sec)
See XtraDB/InnoDB Storage Formats.
The value cut off after that character 💀
Why this happening?
create table tmp2(t1 varchar(100));
insert into tmp2 values('before💀after');
mysql> select * from tmp2;
+--------+
| t1 |
+--------+
| before |
+--------+
1 row in set (0.01 sec)
I ran followed commands and returned some useful information
mysql> SHOW FULL COLUMNS FROM tmp2;
+-------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment |
+-------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| t1 | varchar(100) | utf8_general_ci | YES | | NULL | | select,insert,update,references | |
+-------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
1 row in set (0.00 sec)
and this,
mysql> SELECT character_set_name FROM information_schema.`COLUMNS` WHERE table_schema = "test" AND table_name = "tmp2" AND column_name = "t1";
+--------------------+
| character_set_name |
+--------------------+
| utf8 |
+--------------------+
1 row in set (0.00 sec)
Im testing this on ubuntu/mysql command line.
I found the solution here
I learnt some characters are not includes in utf8
There is a good article here
I needed to change column utf8 to utf8mb4 and it worked
alter table tmp2 modify t1 varchar(100) character set utf8mb4;
SET NAMES utf8mb4;
insert tmp2 values('before💀after');
forgive my newbie question, but why finding by '2' or '2' in Mysql returns the same record?
For example:
Say I have a record with string field named 'slug', and the value is '2'. And the following SQLs returns same record.
SELECT * From articles WHERE slug='2'
SELECT * From articles WHERE slug='2'
It has to do with the collation of your database:
mysql> SHOW VARIABLES LIKE 'collation_%';
+----------------------+-------------------+
| Variable_name | Value |
+----------------------+-------------------+
| collation_connection | latin1_swedish_ci |
| collation_database | latin1_swedish_ci |
| collation_server | latin1_swedish_ci |
+----------------------+-------------------+
3 rows in set (0.00 sec)
mysql> SELECT '2'='2';
+-----------+
| '2'='2' |
+-----------+
| 0 |
+-----------+
1 row in set (0.00 sec)
mysql> SET NAMES 'utf8' COLLATE 'utf8_unicode_ci';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT '2'='2';
+-----------+
| '2'='2' |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)
they should not return the same row for equality, but if you use like you are probably getting the same row. using like mysql will use fuzzy matching, so 2 and 2 will be the same (afer all they are both a form of 2, aren't they?)
What is the datatype of slug? i think its numeric one. If so here mysql does cast it to int, and any ways '2' or ' 2 ' will become 2. This wont happen with string datatypes.