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.
Related
My environment
Mysql 8.0.25
What I want to do
I want to use alter column clause to set default value for my datetime column
Mysql 8 document says that after set default comes literal or expression
https://dev.mysql.com/doc/refman/8.0/en/alter-table.html
...
| ALTER [COLUMN] col_name {
SET DEFAULT {literal | (expr)}
| SET {VISIBLE | INVISIBLE}
| DROP DEFAULT
}
What I tried
so I did below things but none of them was successful.
alter table my_table alter column my_datetime_column set default CURRENT_TIMESTAMP();
alter table my_table alter column my_datetime_column set default NOW();
alter table my_table alter column my_datetime_column set default CURRENT_TIMESTAMP;
alter table my_table alter column my_datetime_column set default NOW;
The question
I know I can set default by change column clause. but why not with alter column?
Is there something I got wrong about the documentation?
This appears to be a strange gap in the MySQL parser.
For years, MySQL column defaults were required to be either a literal scalar value, or else NULL. Expressions were not supported.
MySQL 8.0 additionally supports the option of using an expression for the default, but it is required syntax that the expression is in parentheses.
CREATE TABLE MyTable (
a INT,
b INT,
c INT DEFAULT a+b, -- ERROR
d INT DEFAULT (a+b) -- CORRECT
);
MySQL timestamp/datetime columns have a special syntax that has been supported since early versions, allowing the keyword CURRENT_TIMESTAMP instead of a literal value. No parentheses required. See https://dev.mysql.com/doc/refman/8.0/en/timestamp-initialization.html
But this does not appear to be supported by the ALTER TABLE...ALTER COLUMN statement:
alter table mytable alter column dt set default current_timestamp;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use
near 'current_timestamp' at line 1
However if you use MySQL 8.0, you can use CURRENT_TIMESTAMP if you follow the newer expression-default syntax, and put it in parentheses:
alter table mytable alter column dt set default (current_timestamp);
Query OK, 0 rows affected (0.01 sec)
You can also use the traditional syntax without parentheses, but not with ALTER COLUMN. You have to use the syntax of MODIFY COLUMN, which requires you to specify the column's data type and nullability as well.
alter table mytable modify column dt datetime not null default current_timestamp;
Query OK, 0 rows affected (0.01 sec)
This is just an odd inconsistency in the SQL parser. The special support for CURRENT_TIMESTAMP as a default was not extended to the ALTER COLUMN clause. This has been reported as a bug, but it was rejected: https://bugs.mysql.com/bug.php?id=31452
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)
Here is a table
CREATE TABLE `mytable` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`val` char(128) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY (val)
) ENGINE=InnoDB DEFAULT CHARSET=ascii;
Any idea why is this happening, I expected it to set id to zero in the first query itself
MariaDB > insert into mytable set id=0, val="" on duplicate key update id=0, val=val;
Query OK, 1 row affected (0.01 sec)
MariaDB > select * from mytable;
+----+-------+
| id | val |
+----+-------+
| 1 | |
+----+-------+
1 row in set (0.00 sec)
MariaDB > insert into mytable set id=0, val="" on duplicate key update id=0, val=val;
Query OK, 2 rows affected (0.01 sec)
MariaDB > select * from mytable;
+----+-------+
| id | val |
+----+-------+
| 0 | |
+----+-------+
1 row in set (0.00 sec)
MariaDB > insert into mytable set id=0, val="" on duplicate key update id=0, val=val;
Query OK, 0 rows affected (0.01 sec)
Any explanation will be appreciated.
Update: I am aware of using AUTO_INCREMENT=0 but the real question here is that query explicitly set id=0, so why it is setting it as 1 in first query. It seems mysql ok to set it 0 in duplicate instance.
Thanks
When inserting a new record, setting an AUTO_INCREMENT column to 0 means "generate a new value for this column" (ref). Values for AUTO_INCREMENT columns start from 1. Thus:
insert into mytable set id=0, val="" on duplicate key update id=0, val=val;
is equivalent to:
insert into mytable set id=1, val="";
The second insert you call would create a duplicate key (for the val field, not the id field). This causes the update statement to be run, thus updating id to zero. The "2 rows affected" message appears because the on duplicate key update statement returns 2 in case an existing row is updated (ref).
The third insert does nothing. Both keys are duplicate, but the existing row doesn't need to be updated because its values are already what you expect them to be. In this case the on duplicate key update statement returns "0 rows affected".
By default, the starting value for AUTO_INCREMENT is 1, and it will increment by 1 for each new record.
To let the AUTO_INCREMENT sequence start with another value, use the following SQL statement:
ALTER TABLE myTabel AUTO_INCREMENT=0;
Credits
The answer about NO_AUTO_VALUE_ON_ZERO is correct, although a bit incomplete. There is an option to sql_mode to allow for an explicit value of zero to be entered in an autoincrement field. By default 0 is treated the same as null. If you add the NO_AUTO_VALUE_ON_ZERO option, you are allowed to specify a zero value in that field. I have this in my cnf file:
sql_mode='NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'
please check NO_AUTO_VALUE_ON_ZERO option.
By default, auto_increment column cannot be inserted zero value.
If you set NO_AUTO_VALUE_ON_ZERO on, you can force to input auto_increment column zero value.
I have been having some difficulty trying to auto increment my ID columns in my MySQL database. The primary keys for each table have already been assigned, so now I am trying to make them auto incremented. I have tried the following with no success:
ALTER TABLE table_name MODIFY COLUMN column_name INT NOT NULL AUTO_INCREMENT;
ALTER TABLE table_name MODIFY column_name INT NOT NULL AUTO_INCREMENT;
ALTER TABLE table_name CHANGE column_name INT NOT NULL AUTO_INCREMENT;
ALTER TABLE database.table_name MODIFY column_name INT NOT NULL AUTO_INCREMENT;
I get a message saying:
0 row(s) affected Records: 0 Duplicates: 0 Warnings: 0
BUT when I try to add values using INSERT INTO table VALUES ('value1', 'value2'); without entering a value for the primary key column, which is listed before the value1 column, MySQL gives me an error:
Error Code 1136. Column count doesn't match value count at row 1
I thought that once I set up auto increment, I would not have to put in a value for the auto incremented column. What am I doing wrong? :(
put NULL for the auto increment column in the INSERT statement.
OR
Change the insert query to:
INSERT INTO table (column1,column2) VALUES ('value1', 'value2');
For the insert statement if the columns are not specified before "VALUES" then mysql expects values for all columns. NULL is allowed for auto increment columns. Mysql ignores the NULL value and sets the auto increment value accordingly.
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.