Restrict varchar() to range a-z - mysql

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

Related

EF Core - Incorrect string value

I am using EF to update a field in my MySql DB and ran across the issue of attempting to save data that is not allowable due to collation. For example, ^âÂêÊîÎôÔûÛŵŷ has characters outside the column with character set of latin1.
Running an update/insert with above example I get the exception:
The database update did not take place due to..Incorrect string value
I know what the problem is, but I don't want to keep the characters, the data being provided is usually via UI which would often control what is passed in, however it is also callable by API allowing whatever data the caller would like to send. In the above case, I would like to drop those characters or just replace with a question mark, basically ignore them.
This system already exists in an older language and the rule to (silently..) ignore them exists, I need the error not to be raised and for it to save what it can. I have seen how I can modify the statements for this, or how I can modify the string data coming in. I have 1000s of these. Is there another method to achieve this?

using INFORMATION_SCHEMA.COLUMNS in a TRIGGER to log changes to _all_ columns?

TRIGGERs can be used to log changes to individual DB columns as described at https://stackoverflow.com/a/779250/569976 but that technique requires you have an IF statement for each column. It's not a huge issue if you're just interested in changes to one column BUT if you're interested in changes to all columns it becomes a bit more unweildy.
I can get all the column names of a table, dynamically, by querying the INFORMATION_SCHEMA.COLUMNS table. My question is... can I use that to dynamically reference the column names? Like in the TRIGGER you'd do OLD.columnName <> NEW.columnName but I don't think you can really make a column name dynamic like that.
In PHP you could use variable variables. eg. $obj->$var. But if MySQL has anything remotely similar that'd be news to me.
Any ideas? Or am I just going to go with the old fashioned approach of writing an IF statement for each of the 100s of columns this table has?
The trigger can only reference identifiers directly. You can't use a variable or an expression to name an identifier.
That would require dynamic SQL with PREPARE and EXECUTE so you could have the statement parsed at runtime from a string, but you can't PREPARE a new statement inside a trigger, because the trigger is already executing in the context of the currently executing statement.
The simplest solution is to write a trigger that references each column directly, with as many IF statements as there are columns in the table (I wonder why you have hundreds of columns in your table; that sounds like a different problem of bad design).
The comments above mention a binary log parser. Debezium is an example of an open-source binlog parser.
MySQL also supports an audit plugin architecture, but frankly the existing implementations of audit plugins are pretty clumsy.
https://www.mysql.com/products/enterprise/audit.html
https://mariadb.com/resources/blog/introducing-the-mariadb-audit-plugin/
https://github.com/mcafee/mysql-audit

If I update a SQL table Scheme. Do I have to update all users DBs linked tables?

I updated the SCHEMA of a live table in MySQL for use in my multi-user database. Each user has their own db and links to the production tables through ODBC.
I have been receiving a write error while trying to test my schema updates. I cannot find the core reason. I hypothesized that because the other users are in the production table but have not been relinked to update the table SCHEMA; That it is causing a conflicting write error on my relinked table.
I added a TINYINT with No NULLS and default value of 0
I double checked all datatypes for incompatibility & have tested the "non relinked" tables in a older version of the DB and confirmed it is working as intended with no errors
I expect/want to be able to edit records without a write error, but am hesitant to update the other users to the new table if it is currently having write errors
After changing the schema of a linked table, it's required to refresh the link on all Access databases connected to it.
You can do this on the ribbon through external data -> linked table manager.
Unfortunately, either all users that have a database need to do this manually, unless you automate the task on startup through vba.
You have two separate issues. To "see" new columns, then yes, you must re-link the tables.
(so above is separate question and separate issue). You thus as a general rule can add new columns to the database (even while in use). However, the client side linked tables will not see the new columns until such time you re-link. This approach (adding new columns, but not yet re-linked from Access) is certainly ok and fine - the only downside is end users can't see nor use the new columns until such time you link. From a developer point of view, this good - since your users will not see nor find new columns until such time you roll out a new front end to each work station.
Ok, now problem and issue number two.
As for adding a new column, then re-linking, and THEN having some issue is really a separate issue. In most cases, if you attempting to use a tiny int as a Boolean (and I think that is your case), then you need to ensure several things:
Do not allow nulls (you seem to have this ok).
Make sure you set a default of 0 (server side) for this column. (you might have not allowed nulls, but without a default, then Access likely will still complain. And this default is important during creating time - since the new column needs to be "filled" with zeros.
Make sure the table has a PK defined.
Consider adding a row version column (I think mySQL has these, not sure but they can help immensely).

Mysql Show Create Trigger - Trigger Name Output

I have two mysql databases that I'd like to keep in sync. When I run
show create trigger tr_del_EmailHash;
from a mysqli connection from a local web page I get slightly different output from each database in that one returns the trigger name in single quotes like this:
CREATE trigger `tr_del_EmailHash` before DELETE
...
and the other returns the trigger name without quotes like this:
CREATE trigger tr_del_EmailHash before DELETE
...
Since I'm trying to store these in source control and be able to diff schema across platforms, this difference is very undesirable. The mysqld.cnf files and the mysql server variables are the same on each server, so I'm at a loss for where to look for what controls whether or not the name of a trigger gets quoted or not by "show create trigger" queries. Can anyone provide some helpful suggestions as to where I should be looking or where this can be adjusted?
The quoting behaviour for show create-statements is controlled with the sql_quote_show_create configuration setting:
If enabled (the default), the server quotes identifiers for SHOW CREATE TABLE and SHOW CREATE DATABASE statements. If disabled, quoting is disabled. This option is enabled by default so that replication works for identifiers that require quoting.
Specifically for triggers, this unfortunately only works for MySQL 8, and only applies to the trigger and table name, not the trigger body. Earlier versions will quote the names as you entered them (which might be under your control, and especially involves the body anyway). This may cause trouble though if you mix MySQL 8 and earlier versions (where some modify the code, others don't), so you may have to decide for one congruent naming schema and adjust that setting accordingly.

MySQL Constraints Involving Non-foreign Key Columns [duplicate]

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!