How to restrict a column value in SQLite / MySQL - mysql

I would like to restrict a column value in a SQL table. For example, the column values can only be "car" or "bike" or "van". My question is how do you achieve this in SQL, and is it a good idea to do this on the DB side or should I let the application restrict the input.
I also have the intention to add or remove more values in the future, for example, "truck".
The type of Databases I am using are SQLite and MySQL.

Add a new table containing these means of transport, and make your column a foreign key to that table. New means of transport can be added to the table in future, and your column definition remains the same.
With this construction, I would definitively choose to regulate this at the DB level, rather than that of the application.

For MySQL, you can use the ENUM data type.
column_name ENUM('small', 'medium', 'large')
See MySQL Reference: The ENUM Type
To add to this, I find it's always better to restrict on the DB side AND on the app side. An Enum plus a Select box and you're covered.

Yes, it is recommended to add check constraints. Check constraints are used to ensure the validity of data in a database and to provide data integrity. If they are used at the database level, applications that use the database will not be able to add invalid data or modify valid data so the data becomes invalid, even if the application itself accepts invalid data.
In SQLite:
create table MyTable
(
name string check(name = "car" or name = "bike" or name = "van")
);
In MySQL:
create table MyTable
(
name ENUM('car', 'bike', 'van')
);

You would use a check constraint. In SQL Server it works like this
ALTER TABLE Vehicles
ADD CONSTRAINT chkVehicleType CHECK (VehicleType in ('car','bike','van'));
I'm not sure if this is ANSI standard but I'm certain that MySQL has a similar construct.

If you want to go with DB-side validation, you can use triggers. See this for SQLite, and this detailed how-to for MySQL.
So the question is really whether you should use Database validation or not. If you have multiple clients -- whether they are different programs, or multiple users (with possibly different versions of the program) -- then going the database route is definitely best. The database is (hopefully) centralized, so you can decouple some of the details of validation. In your particular case, you can verify that the value being inserted into the column is contained in a separate table that simply lists valid values.
On the other hand, if you have little experience with databases, plan to target several different databases, and don't have the time to develop expertise, perhaps simple application level validation is the most expedient choice.

To add some beginner level context to the excellent answer of #NGLN above.
First, one needs to check the foreign key constraint is active, otherwise sqlite won't limit to the input to the column to the reference table:
PRAGMA foreign_key;
...which gives a response of 0 or 1, indicating on or off.
To set the foreign key constraint:
PRAGMA foreign_keys = ON;
This needs to be set to ensure that sqlite3 enforces the constraint.
I found it simplest to just set the primary key of the reference table to be the type. In the OP's example:
CREATE TABLE IF NOT EXISTS vehicle_types(
vehicle_type text PRIMARY KEY);
Then, one can insert 'car', 'bike' etc into the vehicle_types table (and more in the future) and reference that table in the foreign key constraint in the child table (the table in which the OP wished to reference the type of vehicle):
CREATE TABLE IF NOT EXISTS ops_original_table(
col_id integer PRIMARY KEY,
...many other columns...
vehicle_type text NOT NULL,
FOREIGN KEY (vehicle_type) REFERENCES vehicle_types(vehicle_type);
Outwith the scope of the OP's question but also take note that when setting up a foreign key constraint thought should be given to what happens to the column in child table (ops_original_table) if a parent table value (vehicle_types) is deleted or updated. See this page for info

Related

MySQL Unique Constraint based on column value

Let's say I have a table like this:
CREATE TABLE dept (
id VARCHAR(255) NOT NULL PRIMARY KEY,
code VARCHAR(255) NOT NULL,
active BIT NOT NULL,
...
);
Problem:
I want to add a unique constraint on code column. But it should be applied only if active is set to true (uniqueness should be checked only among active records). There can be many records with active = false and the same code so I can't use constraint on multiple columns.
What I tried:
I haven't found any references in the documentation proving that such constraint is possible, but I know it is possible in other databases using unique function-based indexes.
Of course I can write a trigger that will check the invariant on every add/update operation, but I hope there is more efficient solution.
I'm using MySQL 5.7.15.
This simply isn't possible in MySQL, I'm afraid.
I have come "close" to solving this in the past by having a uniquely constrained column which is nullable (replacing both the active and code fields). When NULL - it's "inactive", when anything other than NULL - it has to be unique.
But that doesn't precisely solve the problem you're asking. (Perhaps something better can be suggested if you could update your question to include the bigger picture?)
Otherwise read/write to the table through a stored procedure or - as you've suggested yourself - do something inelegant with triggers.
To solve your problem you need use CHECK clause but it MySQL don't support it. From doc:
The CHECK clause is parsed but ignored by all storage engines. See Section 13.1.18, “CREATE TABLE Syntax”. The reason for accepting but ignoring syntax clauses is for compatibility, to make it easier to port code from other SQL servers, and to run applications that create tables with references.
So you can do this only by check data on application level or insert/update rows in this table by stored procedures.
I sorry this does not really a direct answer your question but:
Maybe you are better off with a different table design? The fact that something you want to do is not supported by your RDBMS is always a strong evidence that you are using it wrong.
Have you thought about creating a dept and an dept_history table, dept containing only the active records? That would solve your problem with the unique constraint.

Can I import an existing table automatically changing primary keys?

I have a table about permissions in my server coming from an previous version of my website, and I need to keep them, but newest web app version has it's own and probably needed basic configurations in this table.
So, I need to import the vanilla data into my table (or viceversa, same result) without overwritting or skipping existing primary keys, this means, automatically updating primary keys to others unused. Is this possible? How?
Yes it is possible. Use a INSERT INTO .. SELECT FROM construct like
insert into new_table(col1, col2, ...,coln)
select col1, col2, ...,coln from old_table;
None, just don't include your PK column in the insert statement and thus if in your imported table PK is an synthetic or auto incremented column then it will generated automatically.
The following is an example of my suggested statement structure -
INSERT INTO tblNewPermissions ( permissionsID,
oldPermission1,
oldPermission2,
newPermission1,
newPermission2 )
SELECT permissionsID,
permission1,
permission2,
"newPermission1DefaultValue",
"newPermission2DefaultValue"
FROM tblOldPermissions;
Note : You will need to ensure that the fields in the new table that are used to store the old data have matching data types.
Note : This approach assumes that the primary key is not an autoincrement field.
If there are any questions or comments on this answer, then please feel free to post a comment accordingly.

Microsoft Access 2007, about column value

I'm pretty new to MS Access 2007, and I wanted to ask about something, that I couldn't find.
Is it possible that in a specific column, say for example: type, to make the only possible values "typea", "typeb"?
Just like the yes/no available option, just that it will contain my own specific values.
Yes you can create a lookup table with the id and description (typea/typeb) values in and then reference this table. You can add a check constraint on the column to ensure the type entered matches the constraint specified. (typea or typeb).
There is a way that involves only the basics. Create a reference table for the valid values of Type. It might have two columns, Id and Description. The primary key is Id.
Put two rows in with Id values of "typea" and "typeb". Put whatever you want for the description. You might use this later.
Use the relationship tool to make the column in your existing table reference the Id column in the types table. This will create a references constraint in the database.
Another response suggested adding a check constraint. That will probably run faster, but may involve more learning on your part.
And, if you ever add a third and fourth type, having a table like the one I've given will make it super easy to modify.

How to deal with duplicates in database?

In a program, should we use try catch to check insertion of duplicate values into tables, or should we check if the value is already present in the table and avoid insertion?
This is easy enough to enforce with a UNIQUE constraint on the database side so that's my recommendation. I try to put as much of the data integrity into the database so that I can avoid having bad data (although sometimes unavoidable).
If this is how you already have it you might as well just catch the mysql exception for duplicate value insertion on such a table as doing the check then the insertion is more costly then having the database do one simple lookup (and possibly an insert).
Depends upon whether you are inserting one, or a million, as well as whether the duplicate is the primary key.
If its the primary key, read: http://database-programmer.blogspot.com/2009/06/approaches-to-upsert.html
An UPSERT or ON DUPLICATE KEY... The idea behind an UPSERT is simple.
The client issues an INSERT command. If a row already exists with the
given primary key, then instead of throwing a key violation error, it
takes the non-key values and updates the row.
This is one of those strange (and very unusual) cases where MySQL
actually supports something you will not find in all of the other more
mature databases. So if you are using MySQL, you do not need to do
anything special to make an UPSERT. You just add the term "ON
DUPLICATE KEY UPDATE" to the INSERT statement:
If it's not the primary key, and you are inserting just one row, then you can still make sure this doesn't cause a failure.
For your actual question, I don't really like the idea of using try/catch for program flow, but really, you have to evaluate readability and user experience (in this case performance), and pick what you think is the best of mix of the two.
You can add a UNIQUE constraint to your table.. Something like
CREATE TABLE IF NOT EXISTS login
(
loginid SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
loginname CHAR(20) NOT NULL,
UNIQUE (loginname)
);
This will ensure no two login names are the same.
you can Create a Unique Composite Key
ALTER TABLE `TableName` ADD UNIQUE KEY (KeyOne, KeyTwo, ...);
you just need to create a unique key in your table so that it will not permit to add the same value again.
You should try inserting the value and catch the exception. In a busy system, if you check for the existience of a value it might get inserted between the time you check and the time you insert it.
Let the database do it's job, let the database check for the duplicate entry.
A database is a computerized representation of a set of business rules and a DBMS is used to enforce these business rules as constraints. Neither can verify a proposition in the database is true in the real world. For example, if the model in question is the employees of an enterprise and the Employees table contains two people named 'Jimmy Barnes' DBMS (nor the database) cannot know whether one is a duplicate, whether either are real people, etc. A trusted source is required to determine existence and identity. In the above example, the enterprise's personnel department is responsible for checking public records, perusing references, ensuring the person is not already on the payroll, etc then allocating an unique employee reference number that can be used as a key. This is why we look for industry-standard identifiers with a trusted source: ISBN for books, VIN for cars, ISO 4217 for currencies, ISO 3166 for countries, etc.
I think it is better to check if the value already exists and avoid the insertion. The check for duplicate values can be done in the procedure that saves the data (using exists if your database is an SQL database).
If a duplicate exists you avoid the insertion and can return a value to your app indicating so and then show a message accordingly.
For example, a piece of SQL code could be something like this:
select #ret_val = 0
If exists (select * from employee where last_name = #param_ln and first_name = #param_fn)
select #ret_val = -1
Else
-- your insert statement here
Select #ret_val
Your condition for duplicate values will depend on what you define as a duplicate record. In your application you would use the return value to know if the data was a duplicate. Good luck!

Unique Constraint with conditions in MYSQL

In postgres we have a constraint defined that essentially allows us to limit the number of entries in a table with a certain value to one. We created this constraint:
create unique index list$default$uk on list_group(visitor_uid) where list_type = 'default';
Which means that the unique constraint is only applied when the list_type='default' so that there can only be one 'default' list per visitor in the table.
It looks like MySql doesn't support the additional where on the unique constraint. Is there another way to support this in the database schema for MySQL?
MYSQL doesn't support such types of constraints.
You should use stored procudures for inserting data instead, so you can do some checking and validation.
Why don't you define your default as such that it must have 1 as primary key? This way a normal unique constraint on the pk would be enough already.
If nothing fits to you, you could also consider changing your data model.
Actually it exists. Most contraints depend on the table Engine.
I think InnoDB supports this.
To do it, you have to add a UNIQUE index with the unique combination:
ALTER TABLE visitor ADD UNIQUE unique_default_visitor( visitor_uid, list_type );
I supposed you'd have to write a trigger to check for it.
I never use MySQL but maybe you can create an index like this:
CREATE UNIQUE INDEX list$default$uk ON list_group ((CASE WHEN list_type='default' THEN NULL ELSE visitor_uid END));
Explanation:
A unique index should not care about NULL values. Therefore, make sure the index expression returns NULL for every row where list_type <> 'default'.
My two cents:
why don't you create a column only to store the unique value (maybe you can call it something like is_list_type_default) and another to store all the values. If you do this, you can put a unique constraint on the first column.