Why "NOT NULL" Doesn't Work in MySQL Client - mysql

I am using MySQL client of version 5.5. Today I tried "NOT NULL" to set an attribute, only find it doesn't work during my test. Anybody helps explain this?
//Create Table
CREATE TABLE state(
state_cd char(2) NOT NULL,
state_name varchar(30)
);
//Insert an "Invalid" Record
INSERT INTO state(state_name)
values('Massachusetts');
//DB Operation succeeds!!!
Query OK, 1 row affected, 1 warning (0.09 sec)
//Check the table
mysql> select * from state;
+----------+---------------+
| state_cd | state_name |
+----------+---------------+
| | Massachusetts |
+----------+---------------+
1 row in set (0.00 sec)
mysql> describe state;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| state_cd | char(2) | NO | | NULL | |
| state_name | varchar(30) | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

If you try to insert or update a NOT NULL column to NULL, MySQL will set it to the default instead (in this case the de-facto default is empty string). MySQL will also issue a warning that you can see with SHOW WARNINGS that should say something about an incorrect column value. It will not prevent you from attempting to insert a null value, but it will not accept the value.
You may want to specify an explicit default value
state_cd char(2) NOT NULL DEFAULT '--'
If you want the query to fail when attempting you can either handle this at the application level or take a look at MySQL server modes, which you can set to TRADITIONAL so INSERT/UPDATE will fail when attempting to add an incorrect value.

Related

MySQL - Create table with current date and return date that adjusts [duplicate]

Pretty straight forward question here, I think this should work but it doesn't. Why doesn't it?
CREATE TABLE INVOICE(
INVOICEDATE DATE NOT NULL DEFAULT CURRENT_DATE
)
It doesn't work because it's not supported
The DEFAULT clause specifies a default value for a column. With one exception, the default value must be a constant; it cannot be a function or an expression. This means, for example, that you cannot set the default for a date column to be the value of a function such as NOW() or CURRENT_DATE. The exception is that you can specify CURRENT_TIMESTAMP as the default for a TIMESTAMP column
http://dev.mysql.com/doc/refman/5.5/en/create-table.html
According to this documentation, starting in MySQL 8.0.13, you will be able to specify:
CREATE TABLE INVOICE(
INVOICEDATE DATE DEFAULT (CURRENT_DATE)
)
MySQL 8.0.13 was released to General Availability in October 2018. The release info is located here.
declare your date column as NOT NULL, but without a default. Then add this trigger:
USE `ddb`;
DELIMITER $$
CREATE TRIGGER `default_date` BEFORE INSERT ON `dtable` FOR EACH ROW
if ( isnull(new.query_date) ) then
set new.query_date=curdate();
end if;
$$
delimiter ;
Currently from MySQL 8 you can set the following to a DATE column:
In MySQL Workbench, in the Default field next to the column, write: (curdate())
If you put just curdate() it will fail. You need the extra ( and ) at the beginning and end.
create table the_easy_way(
capture_ts DATETIME DEFAULT CURRENT_TIMESTAMP,
capture_dt DATE AS (DATE(capture_ts))
)
(MySQL 5.7)
I have the current latest version of MySQL: 8.0.20
So my table name is visit, my column name is curdate.
alter table visit modify curdate date not null default (current_date);
This writes the default date value with no timestamp.
----- 2016-07-04 MariaDB 10.2.1 -- Release Note -- -----
Support for DEFAULT with expressions (MDEV-10134).
----- 2018-10-22 8.0.13 General Availability -- -- -----
MySQL now supports use of expressions as default values in data type specifications. This includes the use of expressions as default values for the BLOB, TEXT, GEOMETRY, and JSON data types, which previously could not be assigned default values at all. For details, see Data Type Default Values.
As the other answer correctly notes, you cannot use dynamic functions as a default value. You could use TIMESTAMP with the CURRENT_TIMESTAMP attribute, but this is not always possible, for example if you want to keep both a creation and updated timestamp, and you'd need the only allowed TIMESTAMP column for the second.
In this case, use a trigger instead.
I came to this page with the same question in mind, but it worked for me!, Just thought to update here , may be helpful for someone later!!
MariaDB [niffdb]> desc invoice;
+---------+--------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------+------+-----+---------+----------------+
| inv_id | int(4) | NO | PRI | NULL | auto_increment |
| cust_id | int(4) | NO | MUL | NULL | |
| inv_dt | date | NO | | NULL | |
| smen_id | int(4) | NO | MUL | NULL | |
+---------+--------+------+-----+---------+----------------+
4 rows in set (0.003 sec)
MariaDB [niffdb]> ALTER TABLE invoice MODIFY inv_dt DATE NOT NULL DEFAULT (CURRENT_DATE);
Query OK, 0 rows affected (0.003 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [niffdb]> desc invoice;
+---------+--------+------+-----+-----------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------+------+-----+-----------+----------------+
| inv_id | int(4) | NO | PRI | NULL | auto_increment |
| cust_id | int(4) | NO | MUL | NULL | |
| inv_dt | date | NO | | curdate() | |
| smen_id | int(4) | NO | MUL | NULL | |
+---------+--------+------+-----+-----------+----------------+
4 rows in set (0.002 sec)
MariaDB [niffdb]> SELECT VERSION();
+---------------------------+
| VERSION() |
+---------------------------+
| 10.3.18-MariaDB-0+deb10u1 |
+---------------------------+
1 row in set (0.010 sec)
MariaDB [niffdb]>
While creating a table, you have to use CURRENT_DATE() function as default value. Please see below example I just tested.
CREATE TABLE SALES_DATA (
SALES_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
SALES_GIRL_ID INT UNSIGNED NOT NULL,
SALES_DATE DATE NOT NULL DEFAULT (CURRENT_DATE()),
TOTAL_SALES FLOAT(6, 2),
PRIMARY KEY (SALES_ID),
FOREIGN KEY (SALES_GIRL_ID) REFERENCES SALES_GIRLS(ID)
);

MySQL bigint number - different output in SQL and R

I have stored a value as varchar and as bigint in a MySQL DB:
userID_as_varchar varchar(50) DEFAULT NULL,
userID_as_bigint bigint(20) DEFAULT NULL,
+--------------------+---------------------------+
| userID_as_varchar | userID_as_bigint |
+--------------------+---------------------------+
| 917876131364446205 | 917876131364446200 |
+--------------------+---------------------------+
For any reason, I can't query the full userID_as_bigint value in full precision with SQL, but with R.
Behaviour SQL:
If I query the data or cast it it's always the "rounded" value.
Tested in phpMyAdmin and directly with sql command in shell.
Behaviour R:
If I query the field with R (RMySQL package) the value is complete 917876131364446205
Can anyone explain this behaviour or know a way how to get the full value with SQL.
Best regards.
Not quite sure what you mean, here's a test:
create table test(t1 varchar(50), t2 bigint);
Query OK, 0 rows affected (0.03 sec)
mysql> desc test
-> ;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| t1 | varchar(50) | YES | | NULL | |
| t2 | bigint(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.02 sec)
mysql> insert into test values('917876131364446205', 917876131364446205);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test;
+--------------------+--------------------+
| t1 | t2 |
+--------------------+--------------------+
| 917876131364446205 | 917876131364446205 |
+--------------------+--------------------+
1 row in set (0.00 sec)

CURRENT_DATE/CURDATE() not working as default DATE value

Pretty straight forward question here, I think this should work but it doesn't. Why doesn't it?
CREATE TABLE INVOICE(
INVOICEDATE DATE NOT NULL DEFAULT CURRENT_DATE
)
It doesn't work because it's not supported
The DEFAULT clause specifies a default value for a column. With one exception, the default value must be a constant; it cannot be a function or an expression. This means, for example, that you cannot set the default for a date column to be the value of a function such as NOW() or CURRENT_DATE. The exception is that you can specify CURRENT_TIMESTAMP as the default for a TIMESTAMP column
http://dev.mysql.com/doc/refman/5.5/en/create-table.html
According to this documentation, starting in MySQL 8.0.13, you will be able to specify:
CREATE TABLE INVOICE(
INVOICEDATE DATE DEFAULT (CURRENT_DATE)
)
MySQL 8.0.13 was released to General Availability in October 2018. The release info is located here.
declare your date column as NOT NULL, but without a default. Then add this trigger:
USE `ddb`;
DELIMITER $$
CREATE TRIGGER `default_date` BEFORE INSERT ON `dtable` FOR EACH ROW
if ( isnull(new.query_date) ) then
set new.query_date=curdate();
end if;
$$
delimiter ;
Currently from MySQL 8 you can set the following to a DATE column:
In MySQL Workbench, in the Default field next to the column, write: (curdate())
If you put just curdate() it will fail. You need the extra ( and ) at the beginning and end.
create table the_easy_way(
capture_ts DATETIME DEFAULT CURRENT_TIMESTAMP,
capture_dt DATE AS (DATE(capture_ts))
)
(MySQL 5.7)
I have the current latest version of MySQL: 8.0.20
So my table name is visit, my column name is curdate.
alter table visit modify curdate date not null default (current_date);
This writes the default date value with no timestamp.
----- 2016-07-04 MariaDB 10.2.1 -- Release Note -- -----
Support for DEFAULT with expressions (MDEV-10134).
----- 2018-10-22 8.0.13 General Availability -- -- -----
MySQL now supports use of expressions as default values in data type specifications. This includes the use of expressions as default values for the BLOB, TEXT, GEOMETRY, and JSON data types, which previously could not be assigned default values at all. For details, see Data Type Default Values.
As the other answer correctly notes, you cannot use dynamic functions as a default value. You could use TIMESTAMP with the CURRENT_TIMESTAMP attribute, but this is not always possible, for example if you want to keep both a creation and updated timestamp, and you'd need the only allowed TIMESTAMP column for the second.
In this case, use a trigger instead.
I came to this page with the same question in mind, but it worked for me!, Just thought to update here , may be helpful for someone later!!
MariaDB [niffdb]> desc invoice;
+---------+--------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------+------+-----+---------+----------------+
| inv_id | int(4) | NO | PRI | NULL | auto_increment |
| cust_id | int(4) | NO | MUL | NULL | |
| inv_dt | date | NO | | NULL | |
| smen_id | int(4) | NO | MUL | NULL | |
+---------+--------+------+-----+---------+----------------+
4 rows in set (0.003 sec)
MariaDB [niffdb]> ALTER TABLE invoice MODIFY inv_dt DATE NOT NULL DEFAULT (CURRENT_DATE);
Query OK, 0 rows affected (0.003 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [niffdb]> desc invoice;
+---------+--------+------+-----+-----------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------+------+-----+-----------+----------------+
| inv_id | int(4) | NO | PRI | NULL | auto_increment |
| cust_id | int(4) | NO | MUL | NULL | |
| inv_dt | date | NO | | curdate() | |
| smen_id | int(4) | NO | MUL | NULL | |
+---------+--------+------+-----+-----------+----------------+
4 rows in set (0.002 sec)
MariaDB [niffdb]> SELECT VERSION();
+---------------------------+
| VERSION() |
+---------------------------+
| 10.3.18-MariaDB-0+deb10u1 |
+---------------------------+
1 row in set (0.010 sec)
MariaDB [niffdb]>
While creating a table, you have to use CURRENT_DATE() function as default value. Please see below example I just tested.
CREATE TABLE SALES_DATA (
SALES_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
SALES_GIRL_ID INT UNSIGNED NOT NULL,
SALES_DATE DATE NOT NULL DEFAULT (CURRENT_DATE()),
TOTAL_SALES FLOAT(6, 2),
PRIMARY KEY (SALES_ID),
FOREIGN KEY (SALES_GIRL_ID) REFERENCES SALES_GIRLS(ID)
);

Can a primary key be empty? If yes why did this alter cause this result?

I have the following table:
mysql> DESC my_contacts;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id | varchar(20) | NO | PRI | | |
| location | varchar(20) | YES | | NULL | |
| city | varchar(20) | YES | | NULL | |
| state | varchar(2) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)
If I do a select all I get:
mysql> SELECT * FROM my_contacts;
+----+--------------+------+-------+
| id | location | city | state |
+----+--------------+------+-------+
| 1 | Chester,NJ | NULL | NULL |
| 2 | Katy,TX | NULL | NULL |
| 3 | San Mateo,CA | NULL | NULL |
+----+--------------+------+-------+
3 rows in set (0.00 sec)
I run the following command:
INSERT INTO my_contacts (city,state)
VALUES
(SUBSTRING_INDEX(location,',',1),RIGHT(location,2));
My purpose was to populate the columns city and state with the part before the comma and the part after the comma from the location column.
But the following happened to my table:
mysql> INSERT INTO my_contacts (city,state)
-> VALUES
-> (SUBSTRING_INDEX(location,',',1),RIGHT(location,2));
Query OK, 1 row affected (0.02 sec)
mysql> SELECT * FROM my_contacts;
+----+--------------+------+-------+
| id | location | city | state |
+----+--------------+------+-------+
| | NULL | NULL | NULL |
| 1 | Chester,NJ | NULL | NULL |
| 2 | Katy,TX | NULL | NULL |
| 3 | San Mateo,CA | NULL | NULL |
+----+--------------+------+-------+
4 rows in set (0.00 sec)
I get a record and the id which is the primary key is empty. How is this possible?
I mean it is not NULL but a primary key is not supposed to be empty either right?
You defined your id field as a varchar, which is a dumb idea when you're using it to store integers. an empty field is NOT null. a zero-length string is still a valid string, and therefore a valid id value as far as your table is concerned. Try inserting ANOTHER blank string and you'll get a primary key violation:
INSERT INTO yourtable (id) VALUES (''); // will not work
The id field should be an int type. That'd disallow "empty" values.
primary keys are unique so if you alter the table, then the second row will attempt to add an empty value and fail. as a result, it will attempt the next possible value. If you want the first value not to be empty, you can set a default value.
It's not empty. It's probably an empty string. Note that the datatype is varchar(20).
Well, you didn't assign a value to the primary key field, so the default is NULL.
.
You want to modify the table so the primary key is auto_increment.
You can use a varchar as a foreign key related to another database table, but if you wish to use it as a numerical key, you should utilize a numerical data type such as int.
I know this doesn't answer the precise question regarding the primary key, but as your question does point out the fact you are also having issues parsing out the city and state from your location column, here's the query you would want to use (note you want an UPDATE to modify existing rows, not an INSERT which will add new rows rather than columns):
UPDATE my_contacts
SET
city = substr(location, 1, locate(',', location) - 1),
state = substr(location, locate(',', location) + 1);

mysql aes_encrypt into longtext column

Is it possible to store a MySQL AES_ENCRYPT into a LONGTEXT column?
I know I'm suppose to use varbinary or blob, but I have a table that I'm storing a bunch of random "settings" in, and the settings_value column is longtext.
I went to store a "smtp mail password" in there, and got a little stuck.
If not, I guess, I'll store it as a hex string through php.
SOLUTION:
My query was something like this:
INSERT INTO table (setting_value)VALUES(AES_ENCRYPT('password', 'key')) ON DUPLICATE KEY UPDATE setting_value=VALUES(setting_value)
As you will see in my comments below, I tried changing my column encoding from utf8_unicode_ci to utf8_bin and still it failed. I changed to latin1_bin and it worked.
I switched back to utf8_unicode_ci and changed my query to the following:
INSERT INTO table (setting_value)VALUES(HEX(AES_ENCRYPT('password', 'key'))) ON DUPLICATE KEY UPDATE setting_value=VALUES(setting_value)
That worked since it just turned my value into a hex string.
Took me a second to figure out how to get the value back out correctly, so for documentation purposes:
$pass = SELECT AES_DECRYPT(BINARY(UNHEX(setting_value)), 'key') as orig_text FROM table
echo $pass->orig_text
Did you try it? It's pretty easy to set up a test case, and from what I can see it works fine for your requirements:
mysql> create table t (id int unsigned not null auto_increment primary key, str LONGTEXT);
Query OK, 0 rows affected (0.13 sec)
mysql> desc t;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| str | longtext | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.05 sec)
mysql>
mysql> INSERT INTO t VALUES (1,AES_ENCRYPT('text','password'));
Query OK, 1 row affected (0.02 sec)
mysql>
mysql> select id,str,AES_DECRYPT(str,'password') from t;
+----+-----------------------------+-----------------------------+
| id | str | AES_DECRYPT(str,'password') |
+----+-----------------------------+-----------------------------+
| 1 | ö½¨Ü·øÍJ/ª¼Tf€D | text |
+----+-----------------------------+-----------------------------+
1 row in set (0.00 sec)
Use some binary column type (like BLOB instead of LONGTEXT) for storing AES_ENCRYPTed content.