How to restrict mysql table column to specific value - mysql

I was trying to restrict mySql table column like device_type to android and ios. In table structure i set column device_type to enum with values android and ios.
But while inserting other like xyz it did not give any error or exception it simply leave column as empty.
Is there any way to restrict column to specific values?

I think the best way to approach this is using foreign key constraints. Define a table for device types:
create table DeviceTypes (
DeviceType varchar(255) primary key
);
insert into DeviceTypes(DeviceType)
select 'android' union all select 'ios';
Next, you can add a foreign key constraint to enforce the relationship:
alter table t add constraint fk_t_devicetype foreign key (devicetype) references DeviceTypes(DeviceType);
Attempts to insert values not in the table will result in an error on the insert.
Note that in other databases, you can do essentially the same thing with a check constraint. However, MySQL does not enforce those. You can also do essentially the same thing with a trigger, but those can be a maintenance challenge.
This method also makes it easy to add new device types.
Also, I would typically use a synthetic key for this purpose (that is, an auto-incremented id), but that isn't necessary to get the functionality you want.

Related

Database requires duplicate values as primary key ( Which is not allowed )?

I have a database assignment where I must build the following database.
The issue is, I am given a table to create called dependent which has 5 columns. 1 of these columns is dependent_name. It can't be a Foreign Key because there is not table for the dependents, so I assume it is suppose to be a Primary Key.
When I attempted to add the data in the table I was given an error that says I cannot have duplicate values for primary key.
Of course this is because you cannot have duplicate primary keys ( Alice is a duplicate value in this situation ), but I am not sure how to get around this. I guess I could make another table called dependent_info and make the dependent_name and FK, but this is not stated in the instructions from the teacher.
Is there something I am missing here?

complex mysql constraints over foreign keys

It seems rational to me to stop users or bad codes from inserting invalid data, but I don't remember to see this anywhere!
Consider the following tables
How I can make sure an order is always referencing an address that is created by the same user?
Is this kind of constraint usual and recommended? I mean, Do I even have to care about it in the design?
Since I would not expect a user to be able to place an order without a valid address, therefore I would simply remove the separate FK to the user table, and use the combined user id - address id fields from the address table as a foreign key.
CREATE TABLE orders AS (
--[COLUMN DEFINITIONS]
address_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
CONSTRAINT fk_usr_addr FOREIGN KEY (user_id, address_id)
REFERENCES address(user_id, id)
) ENGINE=InnoDB;
If an order is incomplete and does not have an address yet, then this should not be an issue for a multi column foreign key, since according to mysql documentation on using foreign keys:
The MATCH clause in the SQL standard controls how NULL values in a
composite (multiple-column) foreign key are handled when comparing to
a primary key. MySQL essentially implements the semantics defined by
MATCH SIMPLE, which permit a foreign key to be all or partially NULL.
In that case, the (child table) row containing such a foreign key is
permitted to be inserted, and does not match any row in the referenced
(parent) table. It is possible to implement other semantics using
triggers.

Check the uniqueness using multiple columns including a substring of a field in a mysql table

I have a database table like this.
CREATE TABLE ItemX(
code varchar(20),
size varchar(12),
type varchar(20),
PRIMARY KEY(code),
CONSTRAINT FOREIGN KEY F1(code) REFERENCES Item(code)
);
code is similar to "xxxx-xxxx-xxxx-0001"
I need to check whether (first 15 characters of code,size,type) is unique before adding a row into the table.
I tried UNIQUE (SUBSTRING(code,1,15),size,type) but it didn't work.
How could I achieve this??
ALTER TABLE `ItemX` ADD UNIQUE `ui`(`code`, `size`, `type`);
I'm not sure if MySQL will allow you pass in a function of a column when creating a unique constraint. If you really want to use only the first 15 characters of the code column, you might want to create a new column for this purpose.

Can't create FOREIGN KEY CONSTRAINT in MySQL

I created my MySQL database using phpMyAdmin 3.5.8.1deb1 in Ubuntu.
Instead of that all my tables are InnoDB, I can't add a foreign key, and this is an example:
ALTER TABLE element ADD CONSTRAINT FK_element_id_user FOREIGN KEY (id_user) REFERENCES user(id) ON DELETE SET NULL ON UPDATE CASCADE;
When I run this script I get this error :
#1005 - Can't create table 'tpw.#sql-4d8_e2' (errno: 150) (Details...)
When I click on details I get this :
InnoDB Documentation Supports transactions, row-level locking, and foreign keys
I tried to add the FK manually in the relation view
There could be a couple of things going one here. Here are some things to look for:
Do the data types of each field between the tables match?
Are both both tables using the same MySQL engine?
Here is a good resource to help you debug this issue further.
Excerpt from the resource linked to above:
1) The two key fields type and/or size is not an exact match. For example, if one is INT(10) the key field needs to be INT(10) as well and not INT(11) or TINYINT. You may want to confirm the field size using SHOW CREATE TABLE because Query Browser will sometimes visually show just INTEGER for both INT(10) and INT(11). You should also check that one is not SIGNED and the other is UNSIGNED. They both need to be exactly the same.
2) One of the key field that you are trying to reference does not have an index and/or is not a primary key. If one of the fields in the relationship is not a primary key, you must create an index for that field.
3) The foreign key name is a duplicate of an already existing key. Check that the name of your foreign key is unique within your database. Just add a few random characters to the end of your key name to test for this.
4) One or both of your tables is a MyISAM table. In order to use foreign keys, the tables must both be InnoDB. (Actually, if both tables are MyISAM then you won’t get an error message – it just won’t create the key.) In Query Browser, you can specify the table type.
5) You have specified a cascade ON DELETE SET NULL, but the relevant key field is set to NOT NULL. You can fix this by either changing your cascade or setting the field to allow NULL values.
6) Make sure that the Charset and Collate options are the same both at the table level as well as individual field level for the key columns.
7) You have a default value (ie default=0) on your foreign key column.
8) One of the fields in the relationship is part of a combination (composite) key and does not have it’s own individual index. Even though the field has an index as part of the composite key, you must create a separate index for only that key field in order to use it in a constraint.
9) You have a syntax error in your ALTER statement or you have mistyped one of the field names in the relationship.
10) The name of your foreign key exceeds the max length of 64 chars.
User.ID has to be declared as an INDEX

Can a foreign key reference a non-unique index?

I thought a foreign key meant that a single row must reference a single row, but I'm looking at some tables where this is definitely not the case. Table1 has column1 with a foreign key constraint on column2 in table2, BUT there are many records in table2 with the same value in column2. There's also non-unique index on column2. What does this mean? Does a foreign key constraint simply mean that at least one record must exist with the right values in the right columns? I thought it meant there must be exactly one such record (not sure how nulls fit in to the picture, but I'm less concerned about that at the moment).
update: Apparently, this behavior is specific to MySQL, which is what I was using, but I didn't mention it in my original question.
From MySQL documentation:
InnoDB allows a foreign key constraint to reference a non-unique key. This is an InnoDB extension to standard SQL.
However, there is a pratical reason to avoid foreign keys on non-unique columns of referenced table. That is, what should be the semantic of "ON DELETE CASCADE" in that case?
The documentation further advises:
The handling of foreign key references to nonunique keys or keys that contain NULL values is not well defined (...) You are advised to use foreign keys that reference only UNIQUE (including PRIMARY) and NOT NULL keys.
Your analysis is correct; the keys don't have to be unique, and constraints will act on the set of matching rows. Not usually a useful behavior, but situations can come up where it's what you want.
When this happens, it usually means that two foreign keys are being linked to each other.
Often the table that would contain the key as a primary key isn't even in the schema.
Example: Two tables, COLLEGES and STUDENTS, both contain a column called ZIPCODE.
If we do a quick check on
SELECT * FROM COLLEGES JOIN STUDENTS ON COLLEGES.ZIPCODE = STUDENTS.ZIPCODE
We might discover that the relationship is many to many. If our schema had a table called ZIPCODES, with primary key ZIPCODE, it would be obvious what's really going on.
But our schema has no such table. Just because our schema has no such table doesn't mean that such data doesn't exist, however. somewhere, out in USPO land, there is just such a table. And both COLLEGES.ZIPCODE and STUDENTS.ZIPCODE are references to that table, even if we don't acknowledge it.
This has more to do with the philosophy of data than the practice of building databases, but it neatly illustrates something fundamental: the data has characteristics that we discover, and not only characteristics that we invent. Of course, what we discover could be what somebody else invented. That's certainly the case with ZIPCODE.
Yes, you can create foreign keys to basically any column(s) in any table. Most times you'll create them to the primary key, though.
If you do use foreign keys that don't point to a primary key, you might also want to create a (non-unique) index to the column(s) being referenced for the sake of performance.
Depends on the RDBMS you're using. I think some do this for you implicitly, or use some other tricks. RTM.
PostgreSQL also refuses this (anyway, even if it is possible, it does not mean it is a good idea):
essais=> CREATE TABLE Cities (name TEXT, country TEXT);
CREATE TABLE
essais=> INSERT INTO Cities VALUES ('Syracuse', 'USA');
INSERT 0 1
essais=> INSERT INTO Cities VALUES ('Syracuse', 'Greece');
INSERT 0 1
essais=> INSERT INTO Cities VALUES ('Paris', 'France');
INSERT 0 1
essais=> INSERT INTO Cities VALUES ('Aramits', 'France');
INSERT 0 1
essais=> INSERT INTO Cities VALUES ('Paris', 'USA');
INSERT 0 1
essais=> CREATE TABLE People (name TEXT, city TEXT REFERENCES Cities(name));
ERROR: there is no unique constraint matching given keys for referenced table "cities"
Necromancing.
As others already said, you shouldn't reference a non-unique key as foreign key.
But what you can do instead (without delete cascade danger) is adding a check-constraint (at least in MS-SQL).
That's not exactly the same as a foreign key, but at least it will prevent the insertion of invalid/orphaned/dead data.
See here for reference (you'll have to port the MS-SQL code to MySQL syntax):
Foreign Key to non-primary key
Edit:
Searching for the reasons for the downvote, according to Mysql CHECK Constraint, MySQL doesn't really support CHECK constraints.
You can define them in your DDL query for compatibility reasons, but they are just ignored...
But as mentioned there, you can create a BEFORE INSERT and BEFORE UPDATE trigger, which will throw an error when the requirements of the data are not met, which is basically the same thing, except that it's an even bigger mess.
As to the question:
I thought a foreign key meant that a single row must reference a
single row, but I'm looking at some tables where this is definitely
not the case.
In any sane RDBMS, this is true.
The fact that this is possible in MySQL is just one more reason why
MySQL is an in-sane RDBMS.
It may be fast, but sacrificing referential integrity and data quality on the altar of speed is not my idea of a quality-rdbms.
In fact, if it's not ACID-compliant, it's not really a (correctly functioning) RDBMS at all.
What database are we talking about? In SQL 2005, I cannot create a foreign key constraint that references a column that does not have a unique constraint (primary key or otherwise).
create table t1
(
id int identity,
fk int
);
create table t2
(
id int identity,
);
CREATE NONCLUSTERED INDEX [IX_t2] ON [t2]
(
[id] ASC
);
ALTER TABLE t1 with NOCHECK
ADD CONSTRAINT FK_t2 FOREIGN KEY (fk)
REFERENCES t2 (id) ;
Msg 1776, Level 16, State 0, Line 1
There are no primary or candidate keys in the referenced table 't2'
that match the referencing column list in the foreign key 'FK_t2'.
Msg 1750, Level 16, State 0, Line 1
Could not create constraint. See previous errors.
If you could actually do this, you would effectively have a many-to-many relationship, which is not possible without an intermediate table. I would be truly interested in hearing more about this ...
See this related question and answers as well.