I have inherited an application that uses MySQL and that is used by a PHP front end. The guy that wrote this system has gone to some fairly convoluted lengths to ensure that codes that users enter are valid - and tat means that these codes also exist in another table.
When I first saw this I wondered why he hadn't used CHECK constraints and let the dbms sort this out - I have visions of a load of different programs implementing the same checks instead of just the one place in the dbms. And then I found out that MySQL doesn't support Check constraints (not strictly true - it supports the syntax but just ignores it).
Is there a way that I can implement Check Constraints in MySQL?
Any hints, suggestions etc, would be great.
You can implement something similar to them with triggers, but MySQL itself (before version 8.0.16) doesn't support CHECK constraints. Don't worry though, it'll let you define them and just silently ignore them!
Related
To my dismay (after being so excited to use it), CheckConstraints are not available on MySQL DBs less than 8.0.16. I'm using MySQL 5.7 and doesn't look like I'll be updating any time soon.
I'm using Django v2.2 and wanted to apply the new constraints to my DB:
https://docs.djangoproject.com/en/2.2/ref/models/constraints/
(The docs may need to be updated to say that check constraints don't work with MySQL versions less than xyz)
I want to know if anyone has a good working alternative for this use case.
I've currently whipped up a signal on pre_save to raise an IntegrityError if the constraint matches.
#receiver(pre_save)
def object_constraint(sender, instance, **kwargs):
if issubclass(sender, MyClass):
if instance.constraint_is_met:
raise IntegrityError("What are you even...?")
Thanks
I have a text field in my database and a index on it for the first 10 characters. How do I specify that in my Doctrine Entity?
I can't find any information about database specific options for indexes anywhere :/
This is my "partial" MySQL create statement:
KEY `sourceaddr_index` (`sourceaddr`(10)),
And this is my #Index in doctrine:
#ORM\Index(name="sourceaddr_index", columns={"sourceaddr"}, options={}),
This dosnt interfere with the regular use, but I noticed the problem when deploying development to a new laptop, and creating the database based on my entities...
Any help would be appreciated :)
Possible since Doctrine 2.9, see: https://github.com/doctrine/dbal/pull/2412
#Index(name="slug", columns={"slug"}, options={"lengths": {191}})
Unfortunately, Doctrine seem to be very picky with whitespace location, so e.g. update --dump-sql yields:
DROP INDEX slug ON wp_terms;
CREATE INDEX slug ON wp_terms (slug(191));
and even if you execute those, they messages will stay there (tested with MariaDB 10.3.14).
I've had very good luck naming the index in Doctrine, after manually creating it in MySQL. It's not pretty or elegant, and it's prone to cause errors moving from dev to production if you forget to recreate the index. But, Doctrine seems to understand it respect it.
In my entity, I have the following definition. Doctrine ignores the length option - it's wishful thinking on my part.
/**
* Field
*
* #ORM\Table(name="field", indexes={
* #ORM\Index(name="field_value_bt", columns={"value"}, options={"length": 100})
* })
And in MySQL, I execute
CREATE INDEX field_value_bt ON field (value(100))
As far as I've seen, Doctrine just leaves the index alone so long as it's named the same.
In short: you can't set this within Doctrine. Doctrine's ORM is specifically focused on cross vendor compatability and the type of index you're describing, though supported in many modern RDBMS, is somewhat outside the scope of Doctrine to handle.
Unfortunately there isn't an easy way around this if you use Doctrine's schema updater (in Symfony that would be php app/console doctrine:schema:update --force) as if you manually update the database, Doctrine will sometimes, regress that change to keep things in sync.
In instances where I've needed something like this I've just set up a fixture that sends the relevant ALTER TABLE statement via SQL. If you're going to be distributing your code (i.e. it may run on other/older databases) you can wrap the statement with a platform check to make sure.
It's not ideal but once your app/software stabilises, issues like this shouldn't happen all that often.
I'm working on implementing and designing my first database and have a lot of columns with names and addresses and the like.
It seems logical to place a CHECK constraint on these columns so that the DB only accepts values from an alphanumeric range (disallowing any special characters).
I am using MySQL which, as far as I can tell doesn't support user defined types, is there an easy way to do this?
It seems worth while to prevent bad data from entering the DB, but should this complex checking be offloaded to the application instead?
You can't do it with a CHECK constraint if you're using mysql (question is tagged wth mysql, so I presume this is the case) - mysql doesn't support check constraints. They are allowed in the syntax (to be compatible with DDL from other databases), but are otherwise ignored.
You could add a trigger to the table that fires on insert and update, that checks the data for compliance, but if you find a problem there's no way to raise an exception from a mysql stored proc.
I have used a workaround of hitting a table that doesn't exist, but has a name that conveys the meaning you want, eg
update invalid_characters set col1 = 1;
and hope that the person reading the "table invalid_characters does not exist" message gets the idea.
There are several settings that allows you to change how MySQL handles certain situation (but those aren't enough) for your case.
I would stick with data validation on application side but if you need validation on database side, you have two options:
CREATE PROCEDURE that would validate and insert data, do nothing or raise error by calling SIGNAL
CREATE TRIGGER ... BEFORE INSERT which would validate data and stop insert like suggested in this stackoverflow answer
As per the MySQL manual "The CHECK clause is parsed but ignored by all storage engines." So I know the simple solution is out of the question but is there another feasible means of coming to the same outcome? Maybe through some use of triggers or stored procedures? If so how?
Also since it is just "parsed" is that as good as saying avoid using it since it doesn't serve a purpose?
Using MySQL 5.5.11 and InnoDB tables
Take a look at this interesting article
https://wikis.oracle.com/display/mysql/Triggers#Triggers-EmulatingCheckConstraints
I often use that method.
I am using version 5.5.21
you can use ENUM for check constraints
http://dev.mysql.com/doc/refman/5.0/en/enum.html
I want to have a field in a Mysql table, which should accept inputs having a fixed size - no more, no less. The input data is a number, but solutions for strings can also be considered, as I have no problem storing this data as varchar like stuff.
To be exact, I want a datatype which will NOT allow me to store a number which is having less than 7 or greater than 7 digits. I dont want to use triggers/stored procedures.
This may be possible with a stored procedure, but I wouldn't do this on database level. Validation like this belongs in your application.
I don't believe there is any way to achieve this in MySQL at present without using triggers or stored procedures. If MySQL supported check constraints then you could do it, but it doesn't, so you can't.
The possible solutions are:
TRIGGER on update/insert.
CHECK constraint, but MySQL parses and promptly discards check constraints.
Application-level validation.
Foreign key to a lookup table containing the 900,000 integers of 7 digits.
The only other suggestion is to migrate to a SQL database that supports CHECK constraints.
Open-source databases that support CHECK constraints include:
PostgreSQL
SQLite
Firebird
Apache Derby
HyperSQL
Every commercial database also supports CHECK constraints.
Basically, MySQL is the only SQL database on the market that doesn't support CHECK constraints!