mysql ignoring check constraint - mysql

I have this code and I want to implement it in MySQL but CHECK is not supported. How would I do it?
CREATE TABLE Fare (
type_of_passenger varchar(20),
price FLOAT,
PRIMARY KEY (type_of_passenger),
CHECK (lower(type_of_passenger)='child' OR lower(type_of_passenger)='student' OR lower(type_of_passenger)='senior')
);

Are you sure you need that check? As the primary key is type_of_passenger you will only ever be able to have three rows.. this seems like over-kill
You could just INSERT those 3 rows and move on. If you reference this field in a foreign key, you'll be restricted to the values in the table anyway
In fact as soon as you reference each value with a foreign key that uses ON UPDATE RESTRICT and ON DELETE RESTRICT you won't be able to change them anyway
The only valid concern I can see here is that you want to allow a DB user to change the price but not the type_of_passenger
If you INSERT the correct (or stub) data to start with, you can then control table and column access via permissions
N.B. I would use a surrogate unsigned integer primary here and unique the string description, thus if I do need to change the string I can do it without worry, and without the performance hit of updating all the tables that reference it

It looks like you're really trying to implement an ENUM:
type_of_passenger ENUM('child', 'student', 'senior')
By default MySQL doesn't validate ENUM values, so if you try to store something else it will store an empty string, but if strict SQL mode is enabled it will report an error.
Another alternative is to make this a foreign key to a table where you enter the valid values.
CREATE TABLE passenger_types (
type VARCHAR(20) NOT NULL PRIMARY KEY
);
INSERT INTO passenger_types (type) VALUES
('child'), ('student'), ('senior');
CREATE TABLE Fare (
type_of_passenger varchar(20),
price FLOAT,
PRIMARY KEY (type_of_passenger),
CONSTRAINT FOREIGN KEY (type_of_passenger) REFERENCES passenger_types (type)
);

Related

How to prevent orphaned polymorphic records?

I have a database of polymorphic structure: a "base" type table and two "derived" types:
CREATE TABLE ContactMethod(
id integer PRIMARY KEY
person_id integer
priority integer
allow_solicitation boolean
FOREIGN KEY(person_id) REFERENCES People(id)
)
CREATE TABLE PhoneNumbers(
contact_method_id integer PRIMARY KEY
phone_number varchar
FOREIGN KEY(contact_method_id) REFERENCES ContactMethod(id)
)
CREATE TABLE EmailAddresses(
contact_method_id integer PRIMARY KEY
email_address varchar
FOREIGN KEY(contact_method_id) REFERENCES ContactMethod(id)
)
I want to prevent orphaned ContactMethod records from existing, that is, a ContactMethod record with neither a corresponding PhoneNumber record nor an EmailAddress record. I've seen techniques for ensuring exclusivity (preventing a ContactMethod record with both a related PhoneNumber and EmailAddress), but not for preventing orphans.
One idea is a CHECK constraint that executes a custom function that executes queries. However, executing queries via functions in CHECK constraints is a bad idea.
Another idea is a View that will trigger a violation if an orphaned ContactMethod record is added. The "obvious" way to do this is to put a constraint on the View, but that's not allowed. So it has to be some sort of trick, probably involving an index on the View. Is that really the best (only?) way to enforce no orphans? If so, what is a working example?
Are there other ways? I could get rid of ContactMethod table and duplicate shared columns on the other two tables, but I don't want to do that. I'm primarily curious about capabilities available in MySQL and SQLite, but a solution in any SQL engine would be helpful.
The simplest solution would be to use single table inheritance. So both the contact methods are optional (that is, nullable) fields in the ContactMethod table, but you add a CHECK constraint to ensure at least one of these has a non-null value.
CREATE TABLE ContactMethod(
id integer PRIMARY KEY
person_id integer
priority integer
allow_solicitation boolean,
phone_number varchar DEFAULT NULL
email_address varchar DEFAULT NULL
FOREIGN KEY(person_id) REFERENCES People(id)
CHECK (COALESCE(phone_number, email_address) IS NOT NULL)
)
Another solution that supports polymorphic associations is to reverse the direction of foreign key. Make ContactMethod have a one nullable foreign key for each type of associated method. Use a CHECK to make sure at least one has a non-null value. This works because you don't allow multiple emails or phones per row in ContactMethod. It does mean if you add a different type of contact (e.g. Signal account), then you'd have to add another foreign key to this table.
CREATE TABLE ContactMethod(
id integer PRIMARY KEY
person_id integer
priority integer
allow_solicitation boolean,
phone_number_id integer DEFAULT NULL
email_address_id integer DEFAULT NULL
FOREIGN KEY(person_id) REFERENCES People(id)
FOREIGN KEY(phone_number_id) REFERENCES PhoneNumbers(id)
FOREIGN KEY(email_address_id) REFERENCES EmailAddresses(id)
CHECK (COALESCE(phone_number_id, email_address_id) IS NOT NULL)
)
A newly inserted ContactMethod will always be orphaned until you insert a phone number or an e-mail address. So, you cannot test the condition at insert.
Instead, you could insert contact information with a stored procedure having an optional phone number and optional e-mail parameter in addition to the base information. The base record would only be inserted if at least one of the two has a non-null value.
Then create a delete trigger when a phone number or an e-mail address is deleted, to either delete the ContactMethod record when no related record exist anymore or to raise an exception as shown in Alter a Delete Trigger to Check a Column Value

How to restrict mysql table column to specific value

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.

Allow to assign only one value between two FK columns MYSQL

I tried to find some solution but I couldn't.
Let's supose we have the table bellow and each row of this table needs to be assigned only to one FK (columnfk1 or columnfk2) (Doesn't make sense be assigned to both OR none):
CREATE TABLE example(
id INT UNIQUE AUTO_INCREMENT
,name VARCHAR(255)
,columnfk1 INT
,columnfk2 INT
,FOREIGN KEY (columnfk1) REFERENCES example1(columnfk1)
,FOREIGN KEY (columnfk2) REFERENCES example2(columnfk2)
);
Is there some rule to warrant that each row will have one FK assigned?
I'm using MYSQL 5
Unfortunately, MySQL doesn't support the check constraint, because this can easily be handled using such a constraint:
check (columnfk1 is null or columnfk2 is null);
So, the only way that you can implement this constraint in the database with this data structure is to use a trigger.

How to don´t repeat values stored in database

I´m creating a database addrees and I want to know what I need to set in Mysql to don´t store repeat values?
Like
Addrees 1 ("teste",1,new york,eua);
Addrees 2 ("teste",1,new york,eua);
If this happen my database will not store.
So what I need to do?
To alter an already existing table, run this MySQL command:
alter table yourtablename add unique index(firstcolumn, secondcolumn, thirdcolumn, fourthcolumn);
That'll add the unique constraint to the specified columns. Here's how to specify such a constraint in the CREATE TABLE.
CREATE TABLE buyers (
buyer_id INT UNSIGNED NOT NULL,
first_name CHAR(19) NOT NULL,
last_name CHAR(19) NOT NULL,
age SMALLINT NOT NULL,
post_code SMALLINT NOT NULL,
UNIQUE idx_flname_age (first_name,last_name,age)
);
The primary key constraint will do this too, as mentioned by #Ajeesh
EDIT:
As per the suggestion in the comment, if you want to avoid errors generated by this unique constraint, you have three good options:
INSERT IGNORE
and
INSERT...ON DUPLICATE KEY UPDATE
and
REPLACE
INSERT IGNORE will not do anything if the insert violates the unique constraint, except log a harmless warning. The table will be left as is, and no error would be reported. This may be desireable in some cases.
More commonly is the second option, ON DUPLICATE KEY UPDATE, which says "Well, if the key already exists, then update that key's row like this instead."
And lastly is REPLACE, which will, if the key already exists, delete the row, then do an INSERT as normal. If the key did not exist previously, it will simply act as an INSERT.
This stack overflow answer has some examples.
"INSERT IGNORE" vs "INSERT ... ON DUPLICATE KEY UPDATE"
You need to call these fields a UNIQUE_KEY
To make a column to be distinct you need to have Primary Key constraint/Unique Key. Primary key is used for relating one table with another and it's values should not be NULL. But in your case you can have Unique constraint to store only unique/distinct values.

Add another primary key to table in mysql

I want to add another primary key to a table in mysql.
I use phpmyadmin to communicate with mysql server.
When I click the primary icon for the desired field it gives me this error:
#1075 - Incorrect table definition; there can be only one auto column and it must be defined as a key
Edited:
here's the query:
ALTER TABLE `files` DROP PRIMARY KEY ,ADD PRIMARY KEY ( `file_type` )
How can I do it?
As the name "primary" key says, there may be only one of that (ref: Highlander).
What you might want to try is a UNIQUE KEY, that acts just like a primary for most purpouses. Auto_increment doesn't seem to fulfill any purpouse if used a second time - what'ts the point of two fields carrying exactly the same information?
I believe in your case, what you need is a composite key. I do not know your table structure, but here is a general example taken from here,
CREATE TABLE track(
album CHAR(10),
disk INTEGER,
posn INTEGER,
song VARCHAR(255),
PRIMARY KEY (album, disk, posn)
)
In this case, there is a combination of 3 columns which avoid the duplicate records as you require. Please let me know if I have any mistakes in understanding your scenario.
The error message says it, I think:
the auto_increment column must be key.
So use this query first:
ALTER TABLE 'files' CHANGE 'id' 'id' INT( 10 ) UNSIGNED NOT NULL;
this will remove the auto_increment.
Also, I recommend the Uniqe key as suggested by other answer. I believe there should always (almost) be an Id column in each table.
We can Give Primary Key only once for a table. You can prefer UNIQUE KEY to prevent duplicate records
ALTER TABLE Persons
ADD UNIQUE (P_Id)
You can mark all the fields you want as primary keys, including the existing one. The system internally will drop the existing one and will set all you marked.