I'm playing with MySQL (curiosity, self-learning) and I've noticed a strange thing:
I want to create a table:
use `a`;
CREATE TABLE `Languages` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`LanguageName` char(10) NOT NULL DEFAULT '',
PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
but as the result, the table name is languages instead of Languages. Why ? Should I know something before create a table ?
Check the value of your lower_case_table_names system variable. If this variable has a value of 1, then MySQL converts all table names to lowercase for storage. More information on this behavior can be found here: MySQL Identifier Case Sensitivity
MySQL actually recommends this behavior as a way to avoid data transfer issues (from the doc linked above):
To avoid data transfer problems arising from lettercase of database or
table names, you have two options:
Use lower_case_table_names=1 on all systems. The main disadvantage
with this is that when you use SHOW TABLES or SHOW DATABASES, you do
not see the names in their original lettercase.
Use lower_case_table_names=0 on Unix and lower_case_table_names=2 on
Windows. This preserves the lettercase of database and table names.
The disadvantage of this is that you must ensure that your statements
always refer to your database and table names with the correct
lettercase on Windows. If you transfer your statements to Unix, where
lettercase is significant, they do not work if the lettercase is
incorrect.
SQL is case insensitive in general (keywords and names), so upper/lower cases should not matter. Since mysql maps tables to files (MyISAM tables at least) it makes difference wether you using a Linux or Windows system. Imho you should not create names, where case matters.
Related
I’d like to be able to create MySQL Document Store Collections via simple SQL DDL statements rather than using the X-Protocol clients.
Is there any way to do so?
Edit: I’ll try and clarify the question.
Collections are tables using JSON datatypes and functions. That much is clear.
I would like know how I can create a Collection without using the X-Protocol calls and make sure that the aforementioned collection is picked up as an actual Collection.
Judging from MySQL workbench, collection tables have a _id blob PK with an expression, a doc JSON column and a few other elements I do not recall at the moment (might be indexes, etc).
I have no means to tell via the Workbench whatever additional schema/metadata information is required for a table to be considered a Document Store Collection, or if the mere presence of an _id and doc columns are enough.
I hope this clears things up.
All "x-api" instructions are directly mapped to sql syntax. When you e.g. run db.createCollection('my_collection'), MySQL will literally just execute
CREATE TABLE `my_collection` (
`doc` json DEFAULT NULL,
`_id` varbinary(32) GENERATED ALWAYS AS
(json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
`_json_schema` json GENERATED ALWAYS AS (_utf8mb4'{"type":"object"}') VIRTUAL,
PRIMARY KEY (`_id`),
CONSTRAINT `$val_strict` CHECK (json_schema_valid(`_json_schema`,`doc`))
NOT ENFORCED
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
You can run the corresponding sql statements yourself if you follow that format.
The doc and _id (with their type and the given expression) are required, the _json_schema is optional, the check too (and only added since MySQL 8.0.17). Since MySQL 8, no additional columns are allowed, except generated columns that use JSON_EXTRACT on doc and which are supposed to be used in an index, see below (although they don't actually have to be used in an index).
Any table that looks like that - doc and _id with their correct type/expression and no other columns except an optional _json_schema and generated JSON_EXTRACT(doc,-columns - will be found with getCollections().
To add an index, the corresponding syntax for
my_collection.createIndex("age", {fields: [{field: "$.age", type: "int"}]})
would be
ALTER TABLE `test`.`my_collection` ADD COLUMN `$ix_i_somename` int
GENERATED ALWAYS AS (JSON_EXTRACT(doc, '$.age')) VIRTUAL,
ADD INDEX `age` (`$ix_i_somename`)
Obviously,
db.dropCollection('my_collection')
simply translates to
DROP TABLE `my_collection`
Similarly, all CRUD operations on documents have a corresponding sql DML syntax (that will actually be executed when you use them via x-api).
I am creating a spring profile for dynamic environments in gitlab and don't want to create a separate mysql db for each instance, so what I try is to use my existing liquibase migrations with hsqldb in that speciffic profile, which seems to work besides the engine=InnoDb part in the sql.
I already added sql.syntax_mys=true to the datasource url, which supported the datatypes, not the engine part tho.
Since I want to avoid writing different sql migrations for the dynamic environments and already have a prod instance changing the migration or adding separate migrations is not really an option for me.
Is there a way to tell hsql to just ignore that part, or define it as some function which does nothing?
An example sql would be:
create table if not exists xy(
field1 varchar(255) not null,
field2 ....
) engine=InnoDB;
MySQL supports comments, including a special format for conditional execution:
https://dev.mysql.com/doc/refman/8.0/en/comments.html
If you add a version number after the ! character, the syntax within the comment is executed only if the MySQL version is greater than or equal to the specified version number. The KEY_BLOCK_SIZE keyword in the following comment is executed only by servers from MySQL 5.1.10 or higher:
CREATE TABLE t1(a INT, KEY (a)) /*!50110 KEY_BLOCK_SIZE=1024 */;
HSQLDB also supports comment syntax in SQL statements: http://www.hsqldb.org/doc/1.8/guide/ch09.html#N124ED
All these types of comments are ignored by the database.
Based on this, you could put the ENGINE=InnoDB into a comment so that HSQLDB will ignore it, but MySQL will run it:
create table if not exists xy(
field1 varchar(255) not null,
field2 ....
) /*!10000 engine=InnoDB; */
An automatic stripping feature will be added to HSQLDB in the next version.
In the meantime, you could modify the source code of JDBCStatement to check and strip the string when it is submitted.
Update: A snapshot jar with this feature is now available at http://hsqldb.org/download
1.
When I ran this MYSQL syntax on windows it ran properly:
CREATE TABLE New
(
id bigint NOT NULL AUTO_INCREMENT,
timeUp datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
)
But when I tried running this code on Linux I got an error:
#1067 - Invalid default value for 'time'
2.
On windows the case is not sensitive eg. New and new both are considered to be same. But on linux the case is sensitive.
Configuration of Linux:
MySQL 5.5.33, phpMyAdmin: 4.0.5, PHP: 5.2.17
Configuration of Windows:
MySql: 5.6.11, phpMyAdmin: 4.0.4.1, PHP: 5.5.0
Is there any way to make them common for both systems? Or any alternative approach?
The DEFAULT CURRENT_TIMESTAMP support for a DATETIME (datatype) was added in MySQL 5.6.
In 5.5 and earlier versions, this applied only to TIMESTAMP (datatype) columns.
It is possible to use a BEFORE INSERT trigger in 5.5 to assign a default value to a column.
DELIMITER $$
CREATE TRIGGER ...
BEFORE INSERT ON mytable
FOR EACH ROW
BEGIN
IF NEW.mycol IS NULL THEN
SET NEW.mycol = NOW();
END IF;
END$$
Case sensitivity (of queries against values stored in columns) is due to the collation used for the column. Collations ending in _ci are case insensitive. For example latin1_swedish_ci is case insensitive, but latin1_general_cs is case sensitive.
The output from SHOW CREATE TABLE foo will show the character set and collation for the character type columns. This is specified at a per-column level. The "default" specified at the table level applies to new columns added to the table when the new column definition doesn't specify a characterset.
UPDATE
Kaii pointed out that my answer regarding "case sensitivity" deals with values stored within columns, and whether queries will return a value from a column containing a value of "New" will be returned with a predicate like "t.col = 'new'".
See Kaii's answer regarding identifiers (e.g. table names) being handled differently (by default) on Windows than on Linux.
As the DEFAULT CURRENT_TIMESTAMP question is already answered, i will only respond to the case-sensitivity mismatch in table names between windows and linux.
On Windows, file systems are by default case-insensitive.
But on Linux and other *NIX like Operating Systems, they are case-sensitive by default.
The reason why you get a mismatch in behaviour here is the file system, as each table is created as a separate file and the filesystem handles case-sensitivity for you.
MySQL has a parameter to override this behaviour:
For example, on Unix, you can have two different tables named my_table
and MY_TABLE, but on Windows these two names are considered identical.
To avoid data transfer problems arising from lettercase of database or
table names, you have two options:
Use lower_case_table_names=1 on all systems. The main disadvantage with this is that when you use SHOW TABLES or SHOW DATABASES, you do
not see the names in their original lettercase.
Use lower_case_table_names=0 on Unix and lower_case_table_names=2 on Windows. This preserves the lettercase of database and table names.
The disadvantage of this is that you must ensure that your statements
always refer to your database and table names with the correct
lettercase on Windows. If you transfer your statements to Unix, where
lettercase is significant, they do not work if the lettercase is
incorrect.Exception: If you are using InnoDB tables and you are trying to avoid these data transfer problems, you should set lower_case_table_names=1 on all platforms to force names to be converted to lowercase.
[...]
To avoid problems caused by such differences,
it is best to adopt a consistent convention, such as always creating
and referring to databases and tables using lowercase names. This
convention is recommended for maximum portability and ease of use.
This is an excerpt from the MySQL manual on the case sensitivity of identifiers
if you wants to default time to must change to timestamp in your datatype,
the datetime is going to display the user input of table...
http://dev.mysql.com/doc/refman/5.0/en/timestamp-initialization.html
http://dev.mysql.com/doc/refman/5.6/en/timestamp-initialization.html
The other day I was trying to create a table in mysql usign a standard syntax:
create table client(
rc character varying(11)
constraint client_pk primary key
);
However, mysql doesn't support setting a primary key this way. (I'm 99% sure it's compliant with the sql-92 norm)
So my question: Does MySQL fail to support at even these basic things from a 20 year old standard, or am I missing something?
EDIT: my goal is NOT to create this table using using some mysql dialect, but to create this table using a standardized syntax. And the question is whether it is possible.
To answer your question, no, MySQL is not fully compliant with the SQL-92 specification, in that MySQL supports only a subset of the specification, and MySQL has some significant(ly useful) extensions which are not part of the SQL-92 specification.
This is not just about the SQL syntax that MySQL accepts and recognizes, but (the probably bigger issue) is about what MySQL actually does with the syntax, the actual operations that MySQL performs with the syntax that it does accept. That's really a more important issue than the more superficial issue of what syntax MySQL recognizes.
It's not that MySQL is lazy. And it's not that MySQL just doesn't care.
There is an entire section of the MySQL documentation devoted to MySQL differences from the SQL standard. And the most important differences aren't really about syntax, but rather about that fact that "MySQL performs operations differently in some cases."
For example, MySQL accepts syntax for CHECK constraints, but MySQL does not actually do any checking or make any attempt to enforce CHECK constraints. MySQL accepts syntax that meets the SQL-92 specification, but the behavior of MySQL is much different from other databases that accept that same syntax.
As another example, the behavior of MySQL with respect to FOREIGN KEY constraints differs significantly, depending on whether the storage engine for the table is MyISAM or InnoDB.
To get your CREATE TABLE statement to execute in MySQL, you would need to change it.
It looks like the easiest option for you would be to remove constraint client_pk from the sql text. You can either specify the table constraint in the column definition:
create table client(
rc character varying(11) primary key
);
or declare the table constraint separately"
create table client(
rc character varying(11),
primary key (rc)
);
Both of those forms are entirely compatible with the SQL-92 specification.
Note that MySQL does accept the syntax for constraint name definition, when the declaration of the constraint is not on the column, e.g.
create table client(
rc character varying(11),
constraint client_pk primary key (rc)
);
And that syntax is also entirely compatible with SQL-92 specifiction.
But note that MySQL ignores the supplied constraint name, and assigns the name PRIMARY to the primary key constraint. And this is true even if the constraint is declared in a separate ALTER TABLE statement.
Note that the syntax that MySQL accepts, and in some cases the operations it performs, is dependent on the settings of specific MySQL variables, in particular, sql_mode, and of particular concern, in the case of your statement, the setting of the default-storage-engine variable, and whether this table will be created using the MyISAM engine or the InnoDB engine, or even the corner case that default-storage-engine has been set to BLACKHOLE.
I understand that your goal is to "create this table with standardized syntax".
But I think you really DO need to be concerned with at least some minimum subset of MySQL specific syntax, in as far as the variety of possible behaviors that MySQL can exhibit when presented with "standardized syntax". Consider:
SET default-storage-engine = 'MyISAM' ;
SET default-storage-engine = 'InnoDB' ;
SET sql_mode = '' ;
SET sql_mode = 'ANSI' ;
This works for me in MySQL 5.5.29:
create table client(
rc character varying(11),
constraint client_pk primary key(rc)
);
However, as a_horse_with_no_name has pointed out, MySQL ignores the client_pk name and calls it PRIMARY.
References:
http://savage.net.au/SQL/sql-92.bnf.html
http://owen.sj.ca.us/~rk/howto/sql92.html
create table tablename
(
column_Name varchar(20) not null,
column_Name varchar(20),
primary key(column_name)
);
In this way you can create table and set primary key.
I'm trying to rename my table using this SQL. I'm using MySQL 5.1.41 on Windows XP.
USE 'bobby_tables';
ALTER TABLE gc_acompte_fournisseur
RENAME TO GC_Acompte_Fournisseur;
And the query claims to have executed correctly, but it lies! My table name is still all lower case!
What foul arcanery have I run afoul of that forbids me from capitalizing my tables?
It just how MySQL works on Windows:
http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_lower_case_table_names
lower_case_table_names
If set to 0, table names are stored as
specified and comparisons are case
sensitive. If set to 1, table names
are stored in lowercase on disk and
comparisons are not case sensitive. If
set to 2, table names are stored as
given but compared in lowercase. This
option also applies to database names
and table aliases. For additional
information, see Section 8.2.2,
“Identifier Case Sensitivity”.
You should not set this variable to 0 if you are running MySQL on a system
that has case-insensitive file names
(such as Windows or Mac OS X). If
you set this variable to 0 on such a
system and access MyISAM tablenames
using different lettercases, index
corruption may result. On Windows
the default value is 1. On Mac OS X,
the default value is 2.
If you are using InnoDB tables, you should set this variable to 1 on all
platforms to force names to be
converted to lowercase.
(Emphasis mine)
To rename/alter a table name in mysql, run following query:
RENAME TABLE tbl_name TO new_tbl_name
Example:
RENAME TABLE student TO pu_students
For reference: http://dev.mysql.com/doc/refman/5.0/en/rename-table.html
Thank you!