I have a table set up on a mysql database called "access" with three columns called:
rights_id, (PRIMARY KEY)
username,
name,
In the rights_id column the user can only input 3 different values ("1","2", or "3") 1 means resource, 2 means manager, and 3 means administrator. my problem occurs when there are more than one row with the same rights_id (ie: more than one administrator).It displays an error that tells me i can't have a duplicate entry for the PRIMARY KEY... i was wondering if there was a way to supress this error and allow me to do this? im using vb.net to interact with my MYSQL database running on a Windows 7 OS. Thanks!
rights_id is primary key. You can have only distinct values of primary keys in a table. So consider another primary key or do not use rights_id column this way. You should learn more about relational databases if you would like to use them.
In my opinion the best solution there is to add anothe column id which could be a primary key (you could also set multi-column primary key but this wouldn't fit your data in my opinion).
I'm not sure what "name" means in that table. If it's safe for me to ignore it . . .
If each username can have only one "rights_id", then the primary key should be username. If each username can have more than one "rights_id"--if user Catcall can have rights_id 1 and 2 at the same time--then your primary key should be the pair of columns (rights_id, username).
Since MySQL doesn't enforce CHECK constraints, you should have a separate table of rights id numbers, containing three rows.
create table rights_ids (
rights_id integer primary key
);
insert into rights_ids values (1);
insert into rights_ids values (2);
insert into rights_ids values (3);
Then you can set a foreign key constraint that will prevent any numbers besides those three from appearing in the table named "access". Something like
alter table access
add constraint foreign key (rights_id) references rights_ids (rights_id);
Create a compound PRIMARY KEY of rights_id and username (if usernames are unique that is).
No, you can't suppress that error. The issue is that rights_id is NOT your primary key.
The primary key must be able to uniquely identify a row in your table. If you can have more than 1 rights_id entry, then that is NOT able to fulfill the role of a primary key.
Read this wiki article about unique keys (a primary key is a specific type of unique key).
As Shef pointed out, you'll likely want to use a compound primary key of rights_id and username if that combination actually uniquely identifies a single row in the table.
Related
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
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?
As far as I'm aware, you can only assign primary keys and unique columns to foreign keys... yet I have a table that has a primary key between two columns:
alter table NAME add constraint PK primary key(VALUE1, VALUE2)
I'm trying to make Value1 a foreign key in another table, but it's not recognizing it as a primary key or unique - obviously because the primary key is shared between two values... So what do I do from here? I'm pretty new to SQL syntax...
You are correct that you can only assign primary keys and unique columns to foreign keys. I am not much aware of the business requirement here but ideally, you should be having a third table which has the VALUE1 as a primary key. If not you should create one.
The main idea is that you can't link a foreign key to a value that can hold duplicates on the referenced table. So if your main table has a compound key (more than 1 column), linking the foreign key to one (or many but not all) of it's columns would be linking the table to more than one row (since that column might have duplicates by itself).
If you really need to establish the link between the two then you have a problem, either:
Your primary key isn't really 2 or more columns. You can read about normalizing your database (in standard normal forms) to solve this.
Your relationship between the tables isn't 1 to N (it's N to M). You can't add a foreign key, you will have to create a 3rd table with both primary keys to link them.
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.
My table is as follows:
CREATE TABLE IF NOT EXISTS PHONES (
number VARCHAR(10),
id INT,
type VARCHAR(10),
PRIMARY KEY (number),
FOREIGN KEY (id)
REFERENCES TECHNICIANS(id)
ON DELETE CASCADE
) ENGINE = INNODB;
I would like to specify for each id one primary contact number. I was thinking of adding a boolean column, but I can't figure out how to get it to only allow one "true" value per. id.
I'd add a foreign key from TECHNICIANS back to PHONES:
ALTER TABLE TECHNICIANS
ADD COLUMN primary_number VARCHAR(10),
ADD CONSTRAINT FOREIGN KEY (primary_number) REFERENCES PHONES (number)
ON UPDATE CASCADE
ON DELETE SET NULL;
This creates a cyclical reference: technicians references phones, and phones references technicians. This is okay, but it requires special handling when you do things like dropping tables, restoring backups, etc.
You've basically got 3 options...
have a boolean column but it's up to your application to maintain it
have an integer so you store priority (0=prime, 1=secondary, 2=tertiary,...) again you'll have to maintain it
Have a parent-child relationship so a parent (technician?) record has multiple child (phone number) records. The parent record would then also contain the Id of the primary child record. The only down-side is that adding records either becomes multi-step (add technician, add phone numbers, set primary phone number for technician) or you'll need a smart DAL which does it for you :)
Incidentally, I'm assuming you actually mean one primary number per TechnicianId not per PhoneId
Use a "loophole" in MySQL. The MySQL documentation says:
A UNIQUE index creates a constraint
such that all values in the index must
be distinct. An error occurs if you
try to add a new row with a key value
that matches an existing row. This
constraint does not apply to NULL
values except for the BDB storage
engine. For other engines, a UNIQUE
index permits multiple NULL values for
columns that can contain NULL.
This means that you can create a boolean column that has two values: true (or 1) and NULL.
Create a UNIQUE index over that column + your key. That allows you to only set one record to true, but any number of them can have NULL.