I've create a table called Students.
It has 4 fields: Name, Age, Class, Years.
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| Name | varchar(50) | NO | PRI | NULL | |
| Age | smallint | YES | | 18 | |
| Class | varchar(10) | YES | | NULL | |
| Years | smallint | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
I have added a CHECK CONSTRAINT on Years field that means that the value in Years column can't be lower than 3.
I did it by
mysql> alter table Students
-> add constraint CK_Years check (Years >= 3);
My goal here is to insert a query with a record which has a Years value of 2, which means it won't pass the CK_Years check constraint.
I want to do it without changing the constraint or the fields in the insert statement.
Is it possible?
mysql> insert into Students
-> (Name, Age, Class, Years) values ("Eric","25","110","2");
I have tried:
mysql> alter table Students
-> NOCHECK CONSTRAINT CK_Years;
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 'NOCHECK CONSTRAINT CK_Years' at line 2
I want to disable it just for this insert, and then bring it back (the check constraint).
As you can see, I got this error.
I tried to write it in couple ways. Wit 'CK_Years' or CK_Years or
`CK_Years`
got the same error for all of these ways.
I have verified that I have the constraint in the table:
mysql> select * from INFORMATION_SCHEMA.TABLE_CONSTRAINTS
-> where table_name='Students';
+--------------------+-------------------+-----------------+--------------+------------+-----------------+----------+
| CONSTRAINT_CATALOG | CONSTRAINT_SCHEMA | CONSTRAINT_NAME | TABLE_SCHEMA | TABLE_NAME | CONSTRAINT_TYPE | ENFORCED |
+--------------------+-------------------+-----------------+--------------+------------+-----------------+----------+
| def | School | PRIMARY | School | Students | PRIMARY KEY | YES |
| def | School | CK_Years | School | Students | CHECK | YES |
+--------------------+-------------------+-----------------+--------------+------------+-----------------+----------+
So how can I do it without changing the constraint or the fields in the insert statement?
How can I fix the syntax error?
And what is the reason for it?
Thanks.
MySQL does support syntax to alter a check constraint so it is not enforced, but it's different from the Microsoft SQL Server syntax.
mysql> alter table students alter check CK_Years NOT ENFORCED;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into students values ('Eric',25,'110',2);
Query OK, 1 row affected (0.00 sec)
It's documented here: https://dev.mysql.com/doc/refman/8.0/en/alter-table.html
If you re-enable it, the constraint is enforced, and if you had inserted any rows that violate the constraint, you get an error trying to re-enable it.
mysql> alter table students alter check CK_Years ENFORCED;
ERROR 3819 (HY000): Check constraint 'CK_Years' is violated.
Also once you make the constraint not enforced, it would take effect for all clients, not just for one INSERT.
So I don't think you can do what you intend with a CHECK constraint. You may have to write a trigger that enforces a similar condition on that column, but has logic to enforce it conditionally.
Or do what most developers did before MySQL supported CHECK constraints: enforce it in the client app, before doing the INSERT. Then you can apply any conditions you want.
Related
I have been trying to alter a table to include a date column with default value of CURDATE() but MySQL is constantly throwing syntax error. Now, I have checked syntax for altering a table from several sources but I believe I do not have any syntax error. When I remove the default value part, the query runs fine but for some reason it cannot add a default value for the date column. I don't know why that is the case.
The code:
mysql> describe test;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| col1 | int | YES | | 0 | |
| col2 | varchar(100) | YES | | hello | |
| col3 | varchar(5) | YES | | T | |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.02 sec)
mysql> ALTER TABLE test ADD COLUMN col4 DATE DEFAULT CURDATE();
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 'CURDATE()' at line 1
mysql>
Edit: My MySQL version: 8.0.31
I think it has to be like this now:
ALTER TABLE test ADD COLUMN col4 DATE DEFAULT (CURRENT_DATE);
Note the parenthesis, or (curdate())
I have a MySQL database And I want to add a column:
MariaDB [(none)]> use myDatabase;
Database changed
MariaDB [myDatabase]>
ALTER TABLE material add new_column FLOAT;
But I get the following error:
ERROR 1054 (42S22): Unknown column '`myDatabase`.`m`.`existing_column`' in 'CHECK'
Sure enough, the existing_column is in the table material:
MariaDB [myDatabase]> describe material;
+------------------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| existing_column | tinyint(1) | YES | | NULL | |
+------------------------------+--------------+------+-----+---------+----------------+
42 rows in set (0.003 sec)
(i've left out the other columns for clarity)
And there is a CHECK constraint in place:
MariaDB [myDatabase]> SELECT * FROM INFORMATION_SCHEMA.CHECK_CONSTRAINTS WHERE `TABLE_NAME` = "material";
+--------------------+-------------------+------------+-----------------+-------------------------------------+
| CONSTRAINT_CATALOG | CONSTRAINT_SCHEMA | TABLE_NAME | CONSTRAINT_NAME | CHECK_CLAUSE |
+--------------------+-------------------+------------+-----------------+-------------------------------------+
| def | myDatabase | material | CONSTRAINT_1 | `existing_column` in (0,1) |
+--------------------+-------------------+------------+-----------------+-------------------------------------+
2 rows in set (0.007 sec)
I've tried:
Making sure all values in existing_column are either 0 or 1 -> No change
Dropping the CHECK -> I just get the same error when I try:
MariaDB [myDatabase]> alter table material drop constraint CONSTRAINT_1;
ERROR 1054 (42S22): Unknown column '`myDatabase`.`m`.`existing_column`' in 'CHECK'
making an sqldump and importing it on another system -> No error and I can add my column!
Context:
I'm using mysql 10.3.29 on Debian 10
I normally use flask-sqlalchemy and flask-migrate for managing migrations. That's where I got the error initially.
I don't really need the CHECK constraint. Sqlalchemy added it automatically
Linking this issue here because it's similar: MariaDB: ALTER TABLE command works on one table, but not the other
I was running MariaDB on Debian: 10.5.10-MariaDB-1:10.5.10+maria~buster
I could apply schema to other databases, but I was getting stuck on one table that kept raising the same error:
ERROR 1054 (42S22): Unknown column '`database`.`table`.`col`' in 'CHECK'
Updating MariaDB to 10.5.15 allowed me to apply the schema. It might have just needed a restart - but impossible to know now.
ALL,
igor#IgorDellGentoo ~ $ isql myodbc-5.2-test root wasqra
+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+
SQL> use draft;
SQLRowCount returns 0
SQL> ALTER TABLE owners ADD FOREIGN KEY id REFERENCES leagues(id);
[ISQL]ERROR: Could not SQLExecute
SQL>
What am I doing wrong?
Also, for some reason I can't create a foreign key thru the mySQL-Workbench when creating the table.
There is no "Add" button or "+" sign to add this constraint. And there is no reaction on the right click.
Could someone please point me to the right direction?
I have Workbench version 6.3.4.0 on Gentoo Linux.
SQL> show tables;
+-----------------------------------------------------------------+
| Tables_in_draft |
+-----------------------------------------------------------------+
| leagues |
| owners |
+-----------------------------------------------------------------+
SQLRowCount returns 2
2 rows fetched
SQL> SELECT * FROM leagues;
+-----------+-----------------------------------------------------------------------------------------------------+-----------+------------+-----------+-----------+-----------+-------------+
| id | name | drafttype | scoringtype| roundvalue| leaguetype| salary | benchplayers|
+-----------+-----------------------------------------------------------------------------------------------------+-----------+------------+-----------+-----------+-----------+-------------+
+-----------+-----------------------------------------------------------------------------------------------------+-----------+------------+-----------+-----------+-----------+-------------+
seems you are using id as a foreign key use proper column instead
ALTER TABLE owners
ADD COLUMN FOREIGNID INT NOT NULL;
ALTER TABLE owners
ADD FOREIGN KEY (FOREIGNID) REFERENCES leagues(ID);
I am trying to use ON DELETE CASCADE for a database I'm working on. Didn't seem to work so I tested it out on a simple example with no success.
CREATE TABLE foo (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
data VARCHAR(10),
PRIMARY KEY (id)
)ENGINE=InnoDB;
CREATE TABLE foo2 (
id INT UNSIGNED NOT NULL,
data2 VARCHAR(10),
PRIMARY KEY (id),
CONSTRAINT fk_foo2_id FOREIGN KEY (id) REFERENCES foo(id) ON DELETE CASCADE
)ENGINE=InnoDB;
INSERT INTO foo (data) VALUE ('hello'),('world'),('mysql');
INSERT INTO foo2 (data2) VALUE ('hello2'),('world2'),('mysql2');
SELECT * FROM foo;
+----+-------+
| id | data |
+----+-------+
| 1 | hello |
| 2 | world |
| 3 | mysql |
+----+-------+
3 rows in set (0.00 sec)
SELECT * FROM foo2;
+----+--------+
| id | data2 |
+----+--------+
| 1 | hello2 |
| 2 | world2 |
| 3 | mysql2 |
+----+--------+
3 rows in set (0.00 sec)
DELETE FROM foo WHERE id=2;
SELECT * FROM foo;
+----+-------+
| id | data |
+----+-------+
| 1 | hello |
| 3 | mysql |
+----+-------+
2 rows in set (0.00 sec)
SELECT * FROM foo2;
+----+--------+
| id | data2 |
+----+--------+
| 1 | hello2 |
| 2 | world2 |
| 3 | mysql2 |
+----+--------+
3 rows in set (0.00 sec)
I can't for the life of me figure out why this isn't working. I looked at similar questions and answers on here and I did exactly what they said and it still didn't work. Most of them just said to change to ENGINE=InnoDb, but I tried it and no success.
There must be something I'm missing here, and it's probably very obvious.. Monday mornings.
If anyone can shed some light on this little noob problem of mine, I would greatly appreciate it!
Edit: removed the auto_increment from id in foo2 as it did not belong there
The first thing that pops to mind is to check the setting of the foreign_key_checks variable. If that's set to 0 (FALSE), then foreign key constraints are NOT enforced.
SHOW VARIABLES LIKE 'foreign_key_checks'
To enable foeign key constraints, set to the variable to 1
SET foreign_key_checks = 1;
NOTE: this affects only the current session. New sessions inherit the GLOBAL setting.
Also, verify that your tables are actually using the InnoDB engine, and that the foreign keys are defined. Easiest way is to get the output from:
SHOW CREATE TABLE foo;
SHOW CREATE TABLE foo2;
FOLLOWUP
This is something that we expect NOT to be broken in MySQL 5.1.61.
As a workaround, try defining the foreign key constraint as a separate ALTER TABLE statement.
ALTER TABLE foo2
ADD CONSTRAINT fk_foo2_id FOREIGN KEY (id) REFERENCES foo(id) ON DELETE CASCADE ;
I don't see much use in a foreign key constraint between two columns that are both defined with "auto_increment". In your example, you could easily create several rows in table "foo" (without a counterpart in "foo2"), and from then onwards you could not control whether "id" values in both tables match.
I admit I didn't check the documentation, but it would not surprise me if MySQL silently ignored a foreign key constraint for an auto-generated column.
IMNSHO, your table "foo2" should use "id" values which are set explicitly and reference specific rows in "foo", because then it would make sense that deleting such "foo" rows should cascade onto "foo2".
I want to add a second foreign key constraint between data and containers. When I delete a container, the data linked to this container has to be deleted too.
The tables:
mysql> DESCRIBE data;
+------------------------+--------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+--------------+------+-----+---------------------+----------------
| imei | varchar(15) | NO | MUL | NULL |
mysql> DESCRIBE containers;
+--------------------+-------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+-------------+------+-----+---------------------+----------------+
| imei | varchar(15) | NO | MUL | NULL | |
I create a foreign key with this statement:
mysql> ALTER TABLE `data` ADD FOREIGN KEY (`imei`) REFERENCES `containers`(`imei`) ON DELETE CASCADE;
Query OK, 15168 rows affected (0.12 sec)
Records: 15168 Duplicates: 0 Warnings: 0
But the foreign key hasn't been created:
mysql> use INFORMATION_SCHEMA;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> select TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME, REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME from KEY_COLUMN_USAGE where REFERENCED_TABLE_NAME = 'containers';
+----------------+-------------+-----------------------+-----------------------+------------------------+
| TABLE_NAME | COLUMN_NAME | CONSTRAINT_NAME | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME |
+----------------+-------------+-----------------------+-----------------------+------------------------+
| container_logs | imei | container_logs_ibfk_1 | containers | imei |
+----------------+-------------+-----------------------+-----------------------+------------------------+
1 row in set (0.16 sec)
What am I doing wrong?
Not all storage engines support foreign keys; storage engines that does not support certain SQL features however do not generate error, but just ignore the statements (actually the SQL parser is higher layer in the MySQL architecture, which uses lower-level APIs to communicate with the storage engines).
So if you are using MyISAM, you cannot create a foreign key, but no error will be returned