Changing defaults - mysql

Ok let me rephrase. This is what my table is described as.
mysql> describe department;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| dnumber | int(1) | NO | PRI | NULL | |
| dname | varchar(15) | YES | | NULL | |
| mgrssn | varchar(9) | YES | | NULL | |
+---------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
This is what I need my table to be described as:
+--------------+-------------+------+-----+---------+
| Field | Type | Null | Key | Default |
+--------------+-------------+------+-----+---------+
| dnumber | int(1) | NO | PRI | NOT NULL|
| dname | varchar(15) | YES | | NULL |
| mgrssn | varchar(9) | YES | | NULL |
+--------------+-------------+------+-----+---------+
How do I change the default of dnumber to make it not null from null?

Since dnumber is the primary key of the department table, it cannot have a null value.
So, what will happen if you actually try to insert the following?
INSERT INTO department(dname, mgrssn) VALUES ("test", "123456789");
You'd expect the insert to fail with an error. But no, it succeeds, (albeit, with a warning):
mysql> INSERT INTO department(dname, mgrssn) VALUES ("test", "123456789");
Query OK, 1 row affected, 1 warning (0.04 sec)
What just happened? Well, turns out to be one of MySQL's many gotchas, where "NULL is NOT NULL". Today's MySQL manual says pretty much the same thing:
If a column definition includes no explicit DEFAULT value, MySQL determines the default value as described in Section 11.5, “Data Type Default Values”.
So, what actually got inserted? Let's take a look:
mysql> select * from department;
+---------+-------+-----------+
| dnumber | dname | mgrssn |
+---------+-------+-----------+
| 0 | test | 123456789 |
+---------+-------+-----------+
1 row in set (0.00 sec)
What happened here was that MySQL took that insert statement that was implicitly trying to insert NULL into dnumber and quietly converted it to the default value for INT, or 0.
There's also a really good video that describes this and other strange things MySQL does (as compared to PostgreSQL) in more detail.
Finally, let me add one more piece of advice - since it is the primary key, it's a really good practice to make dnumber an auto-incrementing column, like this:
mysql> ALTER TABLE department MODIFY dnumber int(1) AUTO_INCREMENT;
Query OK, 1 row affected (0.27 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> desc department;
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| dnumber | int(1) | NO | PRI | NULL | auto_increment |
| dname | varchar(15) | YES | | NULL | |
| mgrssn | varchar(9) | YES | | NULL | |
+---------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
That way, future inserts into department won't always try to insert another 0 for dnumber causing a duplicate key error, but will instead use the next lowest available integer value, e.g. 1, then 2, then 3, etc.
Hope this helps!

Related

Why does MySQL keep changing my VARCHAR to a TEXT?

I'm experimenting with improving the performance of a certain table in my company's database. This table has 7.9 6.9 million rows with the format:
mysql> show fields from BroadcastLog;
+---------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| broadcast_id | int(10) unsigned | YES | MUL | NULL | |
| author_id | int(10) unsigned | YES | MUL | NULL | |
| type | int(11) | NO | MUL | NULL | |
| origin | int(11) | YES | MUL | NULL | |
| date_created | datetime | NO | MUL | NULL | |
| date_modified | datetime | NO | | NULL | |
| old_status | int(10) unsigned | YES | MUL | NULL | |
| new_status | int(10) unsigned | YES | MUL | NULL | |
| json_data | text | YES | | NULL | |
| log_text | text | YES | | NULL | |
+---------------+------------------+------+-----+---------+----------------+
11 rows in set (0.01 sec)
One of the first places I wanted to look to improve this was changing the two text fields to varchar fields which I know to generally be more efficient. So I gave it a try:
mysql> alter table BroadcastLog modify log_text varchar(2048);
Query OK, 0 rows affected, 1 warning (1 min 13.08 sec)
Records: 0 Duplicates: 0 Warnings: 1
mysql> show warnings;
+-------+------+---------------------------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------------------------+
| Note | 1246 | Converting column 'log_text' from VARCHAR to TEXT |
+-------+------+---------------------------------------------------+
1 row in set (0.01 sec)
It didn't convert!
I tried to get clever. Let's create a new (temporary) column, copy the data, drop the old column, then rename the new one:
mysql> alter table BroadcastLog add column log_text_vc varchar(2048);
Query OK, 0 rows affected, 1 warning (1 min 13.08 sec)
Records: 0 Duplicates: 0 Warnings: 1
mysql> show warnings;
+-------+------+---------------------------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------------------------+
| Note | 1246 | Converting column 'log_text' from VARCHAR to TEXT |
+-------+------+---------------------------------------------------+
1 row in set (0.01 sec)
Couldn't even create a new column!
I tried to get clever-er. Create a new table, copy the data, drop the old columns, copy the data back:
mysql> create table tmp (id INT UNSIGNED PRIMARY KEY, json_data VARCHAR(1024), log_text VARCHAR(2048));
Query OK, 0 rows affected (0.04 sec)
mysql> insert into tmp (id, json_data, log_text) select id, json_data, log_text from BroadcastLog;
Query OK, 6939076 rows affected (5 min 28.12 sec)
Records: 6939076 Duplicates: 0 Warnings: 0
mysql> alter table BroadcastLog drop column json_data;
Query OK, 0 rows affected (1 min 12.36 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table BroadcastLog drop column log_text;
Query OK, 0 rows affected (1 min 9.10 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table BroadcastLog add column json_data varchar(1024);
Query OK, 0 rows affected (1 min 11.52 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table BroadcastLog add column log_text varchar(2048);
Query OK, 0 rows affected (1 min 15.41 sec)
Records: 0 Duplicates: 0 Warnings: 1
mysql> show warnings;
+-------+------+---------------------------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------------------------+
| Note | 1246 | Converting column 'log_text' from VARCHAR to TEXT |
+-------+------+---------------------------------------------------+
1 row in set (0.01 sec)
mysql> show fields from BroadcastLog;
+---------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| broadcast_id | int(10) unsigned | YES | MUL | NULL | |
| author_id | int(10) unsigned | YES | MUL | NULL | |
| type | int(11) | NO | MUL | NULL | |
| origin | int(11) | YES | MUL | NULL | |
| date_created | datetime | NO | MUL | NULL | |
| date_modified | datetime | NO | | NULL | |
| old_status | int(10) unsigned | YES | MUL | NULL | |
| new_status | int(10) unsigned | YES | MUL | NULL | |
| json_data | varchar(1024) | YES | | NULL | |
| log_text | mediumtext | YES | | NULL | |
+---------------+------------------+------+-----+---------+----------------+
11 rows in set (0.01 sec)
So one field was created properly, but the other was still converted to TEXT, despite the field being completely empty with no data in it
I've been Googling around to try and find an answer, but thus far I've turned up nothing.
Create Table Statement
Per the comments, here's the create table statement (after my above changes, so the log_text column and json_data column on my local database may not match the original data I pulled from our production database this morning):
mysql> show create table BroadcastLog\G
*************************** 1. row ***************************
Table: BroadcastLog
Create Table: CREATE TABLE `BroadcastLog` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`broadcast_id` int(10) unsigned DEFAULT NULL,
`author_id` int(10) unsigned DEFAULT NULL,
`type` int(11) NOT NULL,
`origin` int(11) DEFAULT NULL,
`date_created` datetime NOT NULL,
`date_modified` datetime NOT NULL,
`old_status` int(10) unsigned DEFAULT NULL,
`new_status` int(10) unsigned DEFAULT NULL,
`log_text` mediumtext,
PRIMARY KEY (`id`),
KEY `old_status` (`old_status`),
KEY `new_status` (`new_status`),
KEY `broadcast_id` (`broadcast_id`),
KEY `author_id` (`author_id`),
KEY `log_type_and_origin` (`type`,`origin`),
KEY `log_origin` (`origin`),
KEY `bl_date_created` (`date_created`),
CONSTRAINT `fk_BroadcastLog_author_id` FOREIGN KEY (`author_id`) REFERENCES `User` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_BroadcastLog_broadcast_id` FOREIGN KEY (`broadcast_id`) REFERENCES `Broadcast` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=6941898 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
MySQL Version
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.31 |
+-----------+
1 row in set (0.01 sec)
Updated
I updated MySQL and got the same results:
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.23 |
+-----------+
1 row in set (0.00 sec)
mysql> show fields from BroadcastLog;
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id | int unsigned | NO | PRI | NULL | auto_increment |
| broadcast_id | int unsigned | YES | MUL | NULL | |
| author_id | int unsigned | YES | MUL | NULL | |
| type | int | NO | MUL | NULL | |
| origin | int | YES | MUL | NULL | |
| date_created | datetime | NO | | NULL | |
| date_modified | datetime | NO | | NULL | |
| log_text | text | NO | | NULL | |
| json_data | text | YES | | NULL | |
| old_status | int unsigned | YES | MUL | NULL | |
| new_status | int unsigned | YES | MUL | NULL | |
+---------------+--------------+------+-----+---------+----------------+
11 rows in set (0.00 sec)
mysql> alter table BroadcastLog modify log_text varchar(2048);
Query OK, 6939076 rows affected, 1 warning (3 min 22.64 sec)
Records: 6939076 Duplicates: 0 Warnings: 1
mysql> show warnings;
+-------+------+---------------------------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------------------------+
| Note | 1246 | Converting column 'log_text' from VARCHAR to TEXT |
+-------+------+---------------------------------------------------+
1 row in set (0.01 sec)
mysql> show fields from BroadcastLog;
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id | int unsigned | NO | PRI | NULL | auto_increment |
| broadcast_id | int unsigned | YES | MUL | NULL | |
| author_id | int unsigned | YES | MUL | NULL | |
| type | int | NO | MUL | NULL | |
| origin | int | YES | MUL | NULL | |
| date_created | datetime | NO | | NULL | |
| date_modified | datetime | NO | | NULL | |
| log_text | mediumtext | YES | | NULL | |
| json_data | text | YES | | NULL | |
| old_status | int unsigned | YES | MUL | NULL | |
| new_status | int unsigned | YES | MUL | NULL | |
+---------------+--------------+------+-----+---------+----------------+
11 rows in set (0.02 sec)
I will note one difference I saw in the output, which could have an alternate explanation: it now asys "6939076 rows affected" instead of "0 rows affected". Although I spent a couple hours trying to make sense of this behavior so I had already run multiple ALTER TABLE statements before I even started this SO thread. It's possible you only get rows affected the first time you try to change the column and I just missed it. It's also possible MySQL 8 just uses a different metric for "affected rows" and has different output.
Either way, still not converting to VARCHAR for some reason
After some further experimentation and research, I figured out why MySQL wasn't allowing me to convert these field types. The issue for my specific case of only trying to make a VARCHAR(2048) is caused by a poorly configured MySQL instance, but the issue in general could apply to anyone trying to make a VARCHAR(16378) or larger with default configuration.
The main difference between VARCHAR is TEXT is that VARCHAR is stored in the same file on disk as all of the other data in the table whereas TEXT is stored in a separate file elsewhere on disk. This means that when you read a page from disk you are implicitly reading the data for VARCHAR fields, but the data for TEXT fields is only read explicitly if you request those fields (e.g. via SELECT * or naming the field in your SELECT statement). This is the source of the performance improvement of VARCHAR over TEXT.
Because VARCHAR is stored in the table file on disk, a field can only be set to a VARCHAR if the field would fit in the page file. While MySQL's documentation claims that VARCHAR fields have a maximum length of 65535, it does not enforce page files to be 65535 bytes long. In fact, that's not even the default:
https://dev.mysql.com/doc/refman/8.0/en/innodb-init-startup-configuration.html
A minimum file size is enforced for the first system tablespace data file to ensure that there is enough space for doublewrite buffer pages. The following table shows minimum file sizes for each InnoDB page size. The default InnoDB page size is 16384 (16KB). [emphasis mine]
Without modifying your page size, you can't make a VARCHAR field larger than 16384 (actually, you can't make a field larger than 16377, because of how VARCHAR is stored on disk: 4 bytes for a pointer, 2 bytes for a length, 1 byte boolean to declare whether or not it's null, then the actual data is stored in the "variable length" portion of the page)
My problem came from the fact that we have much smaller page sizes configured.
Conclusion
If you ever try to make a VARCHAR field and MySQL automatically converts it to a TEXT field, check your InnoDB page size:
SHOW VARIABLES LIKE "%page_size%";
You're probably trying to make a field that won't fit on the page.
Unfortunately, changing your page size isn't straight-forward. You have to create a whole new database and copy the data over.
Smaller VARCHARs have some obscure advantages over TEXT and especially TINYTEXT.
But, since you what 2K characters, there is no advantage of VARCHAR(2048) over TEXT except for one thing -- complaining if you try to insert more than 2048 characters.
DESCRIBE seems to say that log_text is TEXT. But the SHOW CREATE TABLE (which I trust more) says it is MEDIUMTEXT (with a limit of 16MBytes).

Unable to insert into database despite specifying a default constraint on column

I have the following table in MySQL database:
mysql> describe student;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| name | varchar(50) | YES | | NULL | |
| dob | date | YES | | NULL | |
| reg_no | varchar(20) | NO | PRI | NULL | |
| department | varchar(50) | YES | | NULL | |
| branch | varchar(50) | YES | | NULL | |
| semester | int(11) | YES | | 1 | |
+------------+-------------+------+-----+---------+-------+
6 rows in set (0.01 sec)
When I try to insert into this database without specifying the last value (i.e.semester), it results in an error
mysql> insert into student values('John Smith','1990-01-01','123ABC','Chemistry','Organic Chemistry');
ERROR 1136 (21S01): Column count doesn't match value count at row 1
Why is this not working? Isn't that the whole point of having a default constraint? That the value specified as default gets assigned if it isn't present in the insert query.
If I write the query like this, it works:
mysql> insert into student values('John Smith','1990-01-01','123ABC','Chemistry','Organic Chemistry',DEFAULT);
Query OK, 1 row affected (0.01 sec)
What is happening? Is my syntax wrong? I would like to be able to insert the record without having to specify 'DEFAULT'
If you are not adding values to all the table columns you should specify which columns you add data.
Example:
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
So in your case,
INSERT INTO student(name, dob, regno, department, branch)
VALUES ('John Smith','1990-01-01','123ABC','Chemistry','Organic Chemistry');
your syntax is wrong while inserting default values,so instead of that query use insert into student(name,dob,reg_no,department,branch)values('John Smith','1990-01-01','123ABCF','Chemistry','Organic Chemistry');

MySQL INSERT shows more affected rows than affected

Consider the following three queries.
The first one can only return a single row as bids_buy.id is the primary key.
The second one shows an existing record in entities_has_documents for primary key 3099541982-2536988132, and the third one doesn't execute due to that existing record.
The forth one does execute as expected, but shows two affected rows.
Why does it show two affected rows, and not just one associated with primary key 3099541982-2536988132?
mysql> SELECT bb.bids_sell_id, 2536988132,"pub_bids", NOW(),506836355 FROM bids_buy bb WHERE bb.id=2453409798;
+--------------+------------+----------+---------------------+-----------+
| bids_sell_id | 2536988132 | pub_bids | NOW() | 506836355 |
+--------------+------------+----------+---------------------+-----------+
| 3099541982 | 2536988132 | pub_bids | 2016-04-16 08:19:13 | 506836355 |
+--------------+------------+----------+---------------------+-----------+
1 row in set (0.00 sec)
mysql> SELECT * FROM entities_has_documents;
+-------------+--------------+----------+---------------------+--------------+-----------+------------+-----------+-------------+
| entities_id | documents_id | type | date_added | date_removed | added_by | removed_by | purged_by | date_purged |
+-------------+--------------+----------+---------------------+--------------+-----------+------------+-----------+-------------+
| 2453409798 | 2536988132 | pub_bids | 2016-04-16 08:07:13 | NULL | 506836355 | NULL | NULL | NULL |
| 3099541982 | 2536988132 | pub_bids | 2016-04-16 08:18:53 | NULL | 506836355 | NULL | NULL | NULL |
+-------------+--------------+----------+---------------------+--------------+-----------+------------+-----------+-------------+
2 rows in set (0.00 sec)
mysql> INSERT INTO entities_has_documents(entities_id,documents_id,type,date_added,added_by)
-> SELECT bb.bids_sell_id, 2536988132,"pub_bids", NOW(),506836355 FROM bids_buy bb WHERE bb.id=2453409798;
ERROR 1062 (23000): Duplicate entry '3099541982-2536988132' for key 'PRIMARY'
mysql> INSERT INTO entities_has_documents(entities_id,documents_id,type,date_added,added_by)
-> SELECT bb.bids_sell_id, 2536988132,"pub_bids", NOW(),506836355 FROM bids_buy bb WHERE bb.id=2453409798
-> ON DUPLICATE KEY UPDATE type="pub_bids", added_by=506836355, date_added=NOW(), removed_by=NULL, date_removed=NULL;
Query OK, 2 rows affected (0.00 sec)
Records: 1 Duplicates: 1 Warnings: 0
mysql> EXPLAIN bids_buy;
+--------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | NULL | |
| bids_sell_id | int(10) unsigned | NO | MUL | NULL | |
| stage_buy_id | int(10) unsigned | NO | MUL | NULL | |
+--------------+------------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
mysql> EXPLAIN entities_has_documents;
+--------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+-------+
| entities_id | int(10) unsigned | NO | PRI | NULL | |
| documents_id | int(10) unsigned | NO | PRI | NULL | |
| type | varchar(16) | NO | MUL | NULL | |
| date_added | datetime | NO | | NULL | |
| date_removed | datetime | YES | | NULL | |
| added_by | int(10) unsigned | NO | MUL | NULL | |
| removed_by | int(10) unsigned | YES | MUL | NULL | |
| purged_by | int(10) unsigned | YES | MUL | NULL | |
| date_purged | datetime | YES | | NULL | |
+--------------+------------------+------+-----+---------+-------+
9 rows in set (0.01 sec)
mysql>
EDIT
Per http://php.net/manual/en/pdostatement.rowcount.php
If the last SQL statement executed by the associated PDOStatement was
a SELECT statement, some databases may return the number of rows
returned by that statement. However, this behaviour is not guaranteed
for all databases and should not be relied on for portable
applications.
So, am I just seeing the number or rows returned from my SELECT statement, and not the number or rows affected by my INSERT? Why would MySQL do such a thing?
EDIT DONE
I think it is due to ON DUPLICATE KEY UPDATE modifier as the MYSQL Reference Manual 5.5 as well as MySQL Reference Manual 5.7 says
If you specify ON DUPLICATE KEY UPDATE, and a row is inserted that would cause a duplicate value in a UNIQUE index or PRIMARY KEY, an UPDATE of the old row is performed. The affected-rows value per row is 1 if the row is inserted as a new row, 2 if an existing row is updated, and 0 if an existing row is set to its current values. If you specify the CLIENT_FOUND_ROWS flag to mysql_real_connect() when connecting to mysqld, the affected-rows value is 1 (not 0) if an existing row is set to its current values.”.
In your case you already had a row with primary key value 3099541982-2536988132. Hence the MySQL lets you know that you are trying to insert a row with duplicate Primary or Unique key by indicating 2 rows affected. As the manual also say that ON DUPLICATE KEY UPDATE leads to the sequence of INSERT than UPDATE update command in case of duplicate key whereas it executes only the INSERT command in case the key is not present.
I hope this helps.
UPDATE
Also see this link.

Create table with date column

I want to create a student table with column 'student_birthday' and its format should be dd-mm-yy.
create table `student`.`studentinfo`(
`student_id` int(10) not null auto_increment,
`student_name` varchar(45) not null,
`student_surname` varchar(45) not null,
`student_birthday` date(???),
(some lines of code)
primary key(student_id));
what should be inputted in the (???) to get the right format above?
Just use "DATE" without the brackets. The brackets are only needed for certain column types where you want to specify the maximum number of bytes/characters that can be stored.
For MySQL, it's documented at https://dev.mysql.com/doc/refman/5.7/en/date-and-time-types.html
The following example will explain your problem. I am using MySQL 5.7.18.
Firstly I have described the structure of users table as I am going to create posts table with FOREIGN KEY.
Later I created posts table and it has a DATE field named created with many other columns.
Finally I inserted 1 row in the newly created table.
mysql> desc users;
+-------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| id | bigint(20) | NO | PRI | NULL | |
| fname | varchar(50) | NO | | NULL | |
| lname | varchar(50) | NO | | NULL | |
| uname | varchar(20) | NO | | NULL | |
| email | text | NO | | NULL | |
| contact | bigint(12) | NO | | NULL | |
| profile_pic | text | NO | | NULL | |
+-------------+-------------+------+-----+---------+-------+
7 rows in set (0.00 sec)
mysql> CREATE TABLE posts(id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, title text NOT NULL, description text NOT NULL, posted_by bigint, FOREIGN KEY(posted_by) REFERENCES users(id) ON DELETE CASCADE ON UPDATE RESTRICT , created DATE);
Query OK, 0 rows affected (0.01 sec)
mysql> desc posts;
+-------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| title | text | NO | | NULL | |
| description | text | NO | | NULL | |
| posted_by | bigint(20) | YES | MUL | NULL | |
| created | date | YES | | NULL | |
+-------------+------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
mysql> INSERT INTO posts(title, description, posted_by, created) values("Getting started with MySQL", "Excellent Database system", 1, "2017-05-26");
Query OK, 1 row affected (0.00 sec)
mysql> select * from posts;
+----+----------------------------+---------------------------+-----------+------------+
| id | title | description | posted_by | created |
+----+----------------------------+---------------------------+-----------+------------+
| 1 | Getting started with MySQL | Excellent Database system | 1 | 2017-05-26 |
+----+----------------------------+---------------------------+-----------+------------+
1 row in set (0.00 sec)
mysql>
The datatype date on its own is enough to represent a date value. The format will matter when you are displaying the data, for which you can use the FORMAT function on your date column.
I should add that there is a certain amount of flexibility as to the format when inserting date time literals as documented here.

Can I configure MySQL so that newly added columns allow nulls by default?

Our developers frequently forget to specify that nulls are allowed when adding columns to existing tables. MySQL defaults to not allowing nulls if Null is not included when using the Alter Table command to add a column
Is there a way to configure MySQL so that new columns allow nulls unless Not Null is explicitly included with the alter table command?
We use PHPMyAdmin to alter tables so a method of making all newly added fields allow nulls through PHPMyAdmin would work.
MySQL's default behavior is allowing nulls by default on alter table commands. It probably has something to do with PHPMyAdmin.
mysql> desc foo;
+-----------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| client_id | int(11) | YES | | NULL | |
| item_id | int(11) | YES | | NULL | |
+-----------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> alter table foo add (a char(1));
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc foo;
+-----------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| client_id | int(11) | YES | | NULL | |
| item_id | int(11) | YES | | NULL | |
| a | char(1) | YES | | NULL | |
+-----------+---------+------+-----+---------+-------+
4 rows in set (0.00 sec)
You can specify the DEFAULT NULL when creating the new column like:
ALTER TABLE table
ADD COLUMN column VARCHAR(255) DEFAULT NULL;