I am trying to drop the default value of a timestamp column.
My DDL looks something like this:
CREATE TABLE bills
(
...
created_at TIMESTAMP DEFAULT '1971-01-06 00:00:00',
updated_at TIMESTAMP DEFAULT '1970-01-01 00:00:01',
);
When I try any of the following:
ALTER TABLE bills ALTER COLUMN created_at DROP DEFAULT;
ALTER TABLE bills ALTER COLUMN created_at SET DEFAULT NULL;
ALTER TABLE bills MODIFY COLUMN created_at TIMESTAMP NULL;
ALTER TABLE bills MODIFY COLUMN created_at TIMESTAMP NULL DEFAULT NULL;
ALTER TABLE bills CHANGE COLUMN created_at created_at TIMESTAMP NULL;
ALTER TABLE bills CHANGE COLUMN created_at created_at TIMESTAMP NULL DEFAULT NULL;
The MYSQL shell says it has executed correctly.
However, when I check the DDL again, it is clear nothing has changed.
On the other hand, I can alter the default value to a specified value like so:
ALTER TABLE bills ALTER COLUMN created_at SET DEFAULT '1972-02-02 00:00:00';
And it updates correctly.
Note that the columns are nullable (as you can see by the DDL) and I have put null data values in the "create_at" column.
The MYSQL version I am using is as v5.7.12
Here is more details about the version I am using:
$ mysql --version
mysql Ver 14.14 Distrib 5.7.21, for Linux (x86_64) using EditLine wrapper
Use the CHANGE COLUMN or MODIFY COLUMN versions of the ALTER TABLE syntax. These require you to specify all the attributes of the column that you want to carry over from the old to the new definition (CHANGE also requires the name so that you can rename at the same time).
e.g.
ALTER TABLE bills CHANGE COLUMN created_at created_at TIMESTAMP NULL;
ALTER TABLE bills MODIFY COLUMN updated_at TIMESTAMP NULL;
Here's a sqlfiddle so you can see it working http://sqlfiddle.com/#!9/303110/3
Update
Have you checked the value of the EXPLICIT_DEFAULTS_FOR_TIMESTAMP variable?
Following on from my comments below, I've now succeeded in getting both of your statements to work in mysql 5.7 by setting the variable EXPLICIT_DEFAULTS_FOR_TIMESTAMP = 1;
I'm afraid I can't properly explain the purpose of this variable except to say that it appears to be intended to disable some 'nonstandard' behaviours in TIMESTAMP fields. It's documented here.
I'll quote one bit of this
By default, explicit_defaults_for_timestamp is disabled, which enables
the nonstandard behaviors.
Personally, I think this is the wrong way round, you ought to set the variable to allow the use of 'nonstandard' behaviours if you wish to go down that path. I'd call that a bug.
In your case, and assuming this actually works on your system, disabling the 'nonstandard' behaviour would allow the 'standard' syntax for changing a column default to work.
This is the output on my system
paul#zoltan:~$ mysql --version
mysql Ver 14.14 Distrib 5.7.21, for Linux (x86_64) using EditLine wrapper
mysql> SET ##SESSION.EXPLICIT_DEFAULTS_FOR_TIMESTAMP = 1;
Query OK, 0 rows affected (0.00 sec)
mysql> drop table bills;
Query OK, 0 rows affected (0.17 sec)
mysql> create table bills (
-> id INT AUTO_INCREMENT PRIMARY KEY,
-> created_at TIMESTAMP DEFAULT '1971-01-06 00:00:00',
-> updated_at TIMESTAMP DEFAULT '1970-01-01 01:00:01'
-> );
Query OK, 0 rows affected (0.42 sec)
mysql> alter table bills alter column created_at drop default;
Query OK, 0 rows affected (0.10 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table bills alter column created_at set default null;
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table bills alter column updated_at drop default;
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table bills alter column updated_at set default null;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table bills\G
*************************** 1. row ***************************
Table: bills
Create Table: CREATE TABLE `bills` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
Related
while creating a table I forgot to add a date of birth column. Is there a way to add a NOT NULL column to a table with default value being current date?
You can use alter table. In MySQL 8.0:
alter table mytable
add datetime_of_birth datetime
not null
default (current_date);
In earlier versions, you can't however, have a date column whose value defaults to current_date. This feature is supported for datetimes a and timestamps column only. If you can live with a datetime column, then:
alter table mytable
add datetime_of_birth datetime
not null
default current_timestamp;
You can then ignore the time portion of the column when querying it. If that's not an acceptable solution, then you need to implement the logic with a trigger.
Use alter table:
alter table t add column date_of_birth date;
If your table has rows of data in it, you must either add the column as nullable, or else give it a DEFAULT that will be assigned on every row.
If you don't give a DEFAULT, then a NOT NULL column will attempt to add the "default default." A date's default is '0000-00-00' which is an invalid date, and it will be rejected if you have strict mode set (which I do recommend):
mysql> create table mytable (id int primary key );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into mytable values (1);
Query OK, 1 row affected (0.01 sec)
mysql> alter table mytable add column date_of_birth date not null;
ERROR 1292 (22007): Incorrect date value: '0000-00-00' for column 'date_of_birth' at row 1
The DATETIME or TIMESTAMP data types can be given a default of CURRENT_TIMESTAMP:
mysql> alter table mytable add column date_of_birth datetime not null default current_timestamp;
Query OK, 0 rows affected (0.13 sec)
Records: 0 Duplicates: 0 Warnings: 0
But you said you wanted a column that is DATE, which doesn't allow this:
mysql> alter table mytable add column date_of_birth date not null default current_timestamp;
ERROR 1067 (42000): Invalid default value for 'date_of_birth'
In MySQL 8.0, you can use expressions as defaults (note the extra parentheses around the expression, which are required):
mysql> alter table mytable add column date_of_birth date not null default (curdate());
Query OK, 1 row affected (0.04 sec)
Records: 1 Duplicates: 0 Warnings: 0
If you're using an earlier version of MySQL, then you can't do this in one ALTER TABLE. You must first add the column as a nullable column, then use UPDATE to backfill values into all the existing rows, then ALTER TABLE again to modify the column to be NOT NULL.
I am using an aurora rds (mysql) in a cluster and cannot insert emoji's. The column which I am trying to insert into has the collation:
utf8mb4 - utf8mb4_unicode_ci
I have tried inserting using client and also from mysql workbench writing the query but in both cases I just see ???? in the field.
I have updated the table default character set:
utf8mb4
and default collation:
utf8mb4_unicode_ci
But still getting ??? instead of emoji
Edit 1:
I've tried to edit the parameter group of the cluster and set all character set values to utf8mb4 and all collation values to utf8mb4_unicode_ci but still not working.
Your cluster parameter group should have the following options set:
character_set_client: utf8mb4
character_set_connection: utf8mb4
character_set_database: utf8mb4
character_set_server: utf8mb4
collation_connection: utf8mb4_unicode_ci
collation_server: utf8mb4_unicode_ci
Rebooting your instances after updating this might be required. When you connect to the cluster you want to set the correct collation for your connection, like this:
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
If you run SHOW VARIABLES LIKE "%collation%" after this you should see three variables that all have the correct collation (utf8mb4_unicode_ci).
You also need to convert your tables and columns to the correct charset and collation, this has been answered before on the DBA Stack Exchange: How to easily convert utf8 tables to utf8mb4 in MySQL 5.5
Changing the default character set of a table doesn't alter any of the existing columns. You can run SHOW CREATE TABLE MyTable and see the difference.
For example, we can create a table with an old-fashioned charset:
mysql> create table MyTable (string1 varchar(100) ) default character set = latin1;
mysql> show create table MyTable\G
*************************** 1. row ***************************
Table: MyTable
Create Table: CREATE TABLE `MyTable` (
`string1` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
Next, we change the table's default, but we see that does not change the column. The existing column automatically gets an option showing us what it actually uses for a charset, since it's now different from the table default:
mysql> alter table MyTable default charset = utf8mb4;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table MyTable\G
*************************** 1. row ***************************
Table: MyTable
Create Table: CREATE TABLE `MyTable` (
`string1` varchar(100) CHARACTER SET latin1 DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
The default is used for columns added to the table subsequently:
mysql> alter table MyTable add column string2 varchar(100);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table MyTable\G
*************************** 1. row ***************************
Table: MyTable
Create Table: CREATE TABLE `MyTable` (
`string1` varchar(100) CHARACTER SET latin1 DEFAULT NULL,
`string2` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
To convert the existing column, use CONVERT TO CHARACTER SET. This rewrites the table, converting the existing data of each column if needed:
mysql> alter table MyTable convert to character set utf8mb4;
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table MyTable\G
*************************** 1. row ***************************
Table: MyTable
Create Table: CREATE TABLE `MyTable` (
`string1` varchar(100) DEFAULT NULL,
`string2` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
Now both columns say nothing about their respective charsets, because they match the table's default.
I wrote a detailed blog post (a few years back) explaining how to support emoji and Aurora MySQL in Ruby on Rails here:
https://josephecombs.com/2018/05/06/how-to-support-emojis-with-rails-elasticbeanstalk-and-amazon-aurora
I know external links are frowned upon here, but this could help others in a similar situation. The guide is too long to paste as an answer.
I have a MySQL table with a column named partition. As it's a reserved keyword, I should be able to use backticks to use it in queries. It works with SELECT, but not with ALTER TABLE.
If I try :
ALTER TABLE `table` DROP `partition`;
or
ALTER TABLE `table` CHANGE `partition` `othername` INT;
MySQL complains with the same error :
Error code 1054: Unknown column 'partition' in 'partition function'
I tried in 'terminal', via MySQL Workbench or through Java JDBC, I always get the same error.
Any suggestion to get rid of that column (without losing / re-creating the whole table ...) ?
EDIT:
You can test it with a small table like that :
CREATE TABLE `testpart` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `partition` smallint(6) NOT NULL, UNIQUE KEY `id` (`id`,`partition`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH(partition) PARTITIONS 16;
Then try
ALTER TABLE `testpart` DROP COLUMN `partition`;
the first try is nearly correct, but you must say what to drop COLUMN. try this to delete them. Backticks are also working.
ALTER TABLE `table` DROP COLUMN `partition`;
here is the Manual page from Mariadb : https://mariadb.com/kb/en/mariadb/alter-table/
sample
i must add some infos to my answer:
the table has PARTITION
and the COLUMN that you want to change / remove is the KEY therefore
you must first remove the PARTITION before you can change them
the name of the COLUMN is a KEYWORD, so you must always quote it with backticks
create a table with 16 partitions
MariaDB [yourschema]> CREATE TABLE testpart (
-> id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
-> `PARTITION` SMALLINT(6) NOT NULL,
-> UNIQUE KEY id (id,`PARTITION`)
-> ) ENGINE=MyISAM DEFAULT CHARSET=latin1
-> PARTITION BY HASH (`PARTITION`)
-> PARTITIONS 16 ;
Query OK, 0 rows affected (0.12 sec)
now remove the paritions
MariaDB [yourschema]> ALTER TABLE `testpart` REMOVE PARTITIONING;
Query OK, 0 rows affected (0.35 sec)
Records: 0 Duplicates: 0 Warnings: 0
remove the (or change) the COLUMN
MariaDB [yourschema]> ALTER TABLE `testpart` DROP COLUMN `PARTITION`;
Query OK, 0 rows affected (0.21 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [yourschema]>
Does partition column have int values?
Try changing that accordly.
I have a 4 GB table and the default charset was set to utf8 though I am saving only latin1 characters.
I changed it to latin1 using alter table statement on a test machine.
The index file log_details.MYI was reduced by 5% while there was no difference noted in the data file, log_details.MYD
I have a few questions:
1) Should I alter the table on production? is it worth it?
2) Will it improve the select speed?
3) I guess I can have longer indexes once I change the default charset to latin1. Any
other advantage?
I have also noted that after changing the default charset using alter table statement, the varchar columns types were changed automatically.
Item_ID varchar(32) character set utf8 How do I avoid this?
mysql> create table char_test( id int, Item_ID varchar(32) ) default charset = utf8;
Query OK, 0 rows affected (0.02 sec)
mysql> insert into char_test values (1, 'abc');
Query OK, 1 row affected (0.00 sec)
mysql> show create table char_test\G
*************************** 1. row ***************************
Table: char_test
Create Table: CREATE TABLE `char_test` (
`id` int(11) default NULL,
`Item_ID` varchar(32) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> alter table char_test default charset = latin1;
Query OK, 1 row affected (0.03 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> show create table char_test\G
*************************** 1. row ***************************
Table: char_test
Create Table: CREATE TABLE `char_test` (
`id` int(11) default NULL,
`Item_ID` varchar(32) character set utf8 default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
Performance is probably the last thing you should care about. What character set is you client-side app using? What natural language is the info written on? Those are the questions you must make.
If you stick to Latin1 you won't be able to store Japanese characters but also some common chars like the € symbol. On the other side, using UTF-8 in the database may be useless (or plain wrong) if your application cannot handle multi-byte input.
See log below. (Snipped just for brevity; unsnipped # http://pastebin.com/k9sCM6Ee)
In short: somehow rows are getting assigned ID 0. When this happens, it blocks inserts, even when those inserts aren't actually conflicting with ID 0 (although that really shouldn't happen in the first place).
Although it is heavily read and very heavily inserted (up to ~300k rows/min), this table is never updated. The only method that inserts is the one that results in the INSERT INTO queries like below. There are no foreign keys or the like.
a) WTF?
b) How do I fix it?
Thanks!
$ mysql --version
mysql Ver 14.14 Distrib 5.1.30, for apple-darwin9.4.0 (i386) using readline 5.1
$ mysql
mysql> SHOW CREATE TABLE visitations \G
*************************** 1. row ***************************
Table: visitations
Create Table: CREATE TABLE `visitations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`scraping_id` int(11) NOT NULL,
`site_id` int(11) NOT NULL,
`visited` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `index_visitations_on_scraping_id_and_site_id` (`scraping_id`,`site_id`),
KEY `index_visitations_on_site_id` (`site_id`)
) ENGINE=InnoDB AUTO_INCREMENT=23525407 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> show triggers;
Empty set (0.04 sec)
mysql> INSERT INTO `visitations` (`scraping_id`,`site_id`,`visited`) VALUES (647,196,0),(647,51679,0),(647,13689,0),(647,85739,1),(647,4388,0),(647,100346,0),(647,1245,0),[snip];
ERROR 1062 (23000): Duplicate entry '0' for key 'PRIMARY'
mysql> SELECT * FROM `visitations` WHERE (`scraping_id`,`site_id`,`visited`) IN ((647,196,0),(647,51679,0),(647,13689,0),(647,85739,1),(647,4388,0),(647,100346,0),(647,1245,0),[snip]);
Empty set (1 min 27.43 sec)
mysql> select * from visitations where id = 0;
+----+-------------+---------+---------+
| id | scraping_id | site_id | visited |
+----+-------------+---------+---------+
| 0 | 645 | 46177 | 0 |
+----+-------------+---------+---------+
1 row in set (0.00 sec)
mysql> delete from visitations where id < 363;
Query OK, 363 rows affected (0.11 sec)
mysql> select * from visitations where id = 0;
Empty set (0.00 sec)
mysql> INSERT INTO `visitations` (`scraping_id`,`site_id`,`visited`) VALUES (647,196,0),(647,51679,0),(647,13689,0),(647,85739,1),(647,4388,0),(647,100346,0),(647,1245,0),[snip];
Query OK, 500 rows affected (0.23 sec)
Records: 500 Duplicates: 0 Warnings: 0
mysql> select * from visitations where id = 0;
Empty set (0.00 sec)
mysql> INSERT INTO `visitations` (`scraping_id`,`site_id`,`visited`) VALUES (647,196,0),(647,51679,0),(647,13689,0),(647,85739,1),(647,4388,0),(647,100346,0),(647,1245,0),[snip];
ERROR 1062 (23000): Duplicate entry '647-196' for key 'index_visitations_on_scraping_id_and_site_id'
You have probably hit a bug like:
auto increment does not work properly with InnoDB after update
You need to track the change history from the release you are using to identify whether fixed bugs can affect you and whether you should upgrade.
MySQL 5.1 Change History