Mysql create table with two foreign keys referencing primary key - mysql

I have two mysql tables. The first one is created using the following code:
create table project(
project_id int not null auto_increment,
project_name varchar(30)
primary key(project_id));
The second table:
create table matches(
match_id int not null auto_increment,
match_name varchar(30),
project_id int(4) foreign key (project_id) references projects(project_id));
Both these commands works fine. I want to add the project_name column from the first table to the second table. I tried using
alter table projects drop primary key, add primary key(project_id, project_name);
and then
alter table matches add column project_name varchar(30), add foreign key (project_name) references projects(project_name);
But got the following error:
ERROR 1005 (HY000): Can't create table 'matches.#sql-55e_311' (errno: 150)
How do i include both the columns from the first table into the second table.
The current structure of my second table is as follows:
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| match_id | int(11) | NO | PRI | NULL | auto_increment |
| match_name | varchar(30) | YES | | NULL | |
| project_id | int(4) | NO | MUL | NULL | |
+------------+-------------+------+-----+---------+----------------+
I want to add the project_name as the fourth column in my second table.

To use a compound Primary Key as Foreign Key, you'll have to add the
same number of columns (that compose the PK) with same datatypes to
the child table and then use the combination of these columns in the
FOREIGN KEY definition.
see related post here https://stackoverflow.com/a/10566463/4904726
so try this way
alter table matches add foreign key (project_id, project_name) references projects(project_id, project_name);

Do you understand what a FK constraint says? It says a list of values for some columns in a table must appear as a list of values for some columns forming a (declared) PK or UNIQUE NOT NULL in the referenced table. So what you are writing doesn't make sense. If you wanted a PK (project_id, project_name) then that should also be the form of your FK.
But (project_id, project_name) is not two 1-column PKs, it is one 2-column PK, and it is probably not what you want since presumably in projects it isn't just pairs that are unique it is each column. Presumably you want two 1-column PKs and two one-column FKs, one referencing each PK.
If projects project_id was NOT NULL you could write:
alter table projects add primary key(project_name);
alter table matches add column project_name varchar(30),
add foreign key (project_name) references projects(project_name);
But if project_name can be NULL in projects then you cannot make it a PK and you cannot sensibly have a FK to it. You can make it UNIQUE. Unfortunately MySQL lets you write such a FK declaration to a non-NULL UNIQUE column while it also tells you not to do it:
The handling of foreign key references to non-unique keys or keys that contain NULL values is not well defined for operations such as UPDATE or DELETE CASCADE. You are advised to use foreign keys that reference only keys that are both UNIQUE (or PRIMARY) and NOT NULL.
So if you want projects project_name to be nullable then should declare it UNIQUE but you should enforce the logical matches project_name match with a trigger.

Related

PostgreSQL, MonetDB and MySQL add foreign key to existing table

When I add a foreign key to a table that already has data, what does each of these database management systems do?
Do they analyze each value of the column to confirm it is a value from the referenced table primary key ?
Or do they have some other optimized mechanism ? And if that's the case, what is that mechanism ?
I can't confirm for MonetDB, but in PostgreSQL and MySQL (and most probably on MonetDB too) the answer is yes, they will check every value and will raise an error if the key does not exists on the referenced table.
Notice that the referenced column doesnt need to be the primary key for the referenced table - you can reference any column as a foreign key to the other table.
Yes, of course, a constraint that is not enforced would make no sense.
You can just try(this is for Postgres):
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE one
( one_id SERIAL NOT NULL PRIMARY KEY
, name varchar
);
INSERT INTO one(name)
SELECT 'name_' || gs::text
FROM generate_series(1,10) gs ;
CREATE TABLE two
( two_id SERIAL NOT NULL PRIMARY KEY
, one_id INTEGER -- REFERENCES one(one_id)
);
INSERT INTO two(one_id)
SELECT one_id
FROM one ;
DELETE FROM one WHERE one_id%5=0;
ALTER TABLE two
ADD FOREIGN KEY (one_id) REFERENCES one(one_id)
;
\d one
\d two
Result:
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table tmp.one
drop cascades to table tmp.two
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 10
CREATE TABLE
INSERT 0 10
DELETE 2
ERROR: insert or update on table "two" violates foreign key constraint "two_one_id_fkey"
DETAIL: Key (one_id)=(5) is not present in table "one".
Table "tmp.one"
Column | Type | Modifiers
--------+-------------------+------------------------------------------------------
one_id | integer | not null default nextval('one_one_id_seq'::regclass)
name | character varying |
Indexes:
"one_pkey" PRIMARY KEY, btree (one_id)
Table "tmp.two"
Column | Type | Modifiers
--------+---------+------------------------------------------------------
two_id | integer | not null default nextval('two_two_id_seq'::regclass)
one_id | integer |
Indexes:
"two_pkey" PRIMARY KEY, btree (two_id)
The error message is the same as for an actual insert or update. And you can see that the engine bails out once it en counters the first conflicting row.

Single query to collect data from multiple tables

I have a problem collecting data from an SQL database that I designed.
This is a table of questions of different types, each type has it's own table with different columns and has the questionid as a foreign key that referenced this table as seen below.
Column | Type | Modifiers
------------+------------------------+-----------
questionid | integer | not null
header | character varying(500) |
Indexes:
"quizquestion_pkey" PRIMARY KEY, btree (questionid)
Referenced by:
TABLE "matchingpairs" CONSTRAINT "matchingpairs_questionid_fkey" FOREIGN KEY (questionid) REFERENCES quizquestion(questionid)
TABLE "mcqchoices" CONSTRAINT "mcqchoices_questionid_fkey" FOREIGN KEY (questionid) REFERENCES quizquestion(questionid)
TABLE "questionsinquiz" CONSTRAINT "questionsinquiz_questionid_fkey" FOREIGN KEY (questionid) REFERENCES quizquestion(questionid)
TABLE "truefalsequestion" CONSTRAINT "truefalsequestion_questionid_fkey" FOREIGN KEY (questionid) REFERENCES quizquestion(questionid
)
I have another table that keeps up which question belongs to which quiz using also the questionid
Column | Type | Modifiers
------------+---------+-----------
quizid | integer | not null
questionid | integer | not null
index | integer |
Indexes:
"questionsinquiz_pkey" PRIMARY KEY, btree (quizid, questionid)
Foreign-key constraints:
"questionsinquiz_questionid_fkey" FOREIGN KEY (questionid) REFERENCES quizquestion(questionid)
"questionsinquiz_quizid_fkey" FOREIGN KEY (quizid) REFERENCES quiz(quizid)
Is there a way to collect all the different questions in one query or do I have to query on every question type, or is there something different that I can change in the database table design.
Based on your description, you can use Postgres inheritance. This is a facility where tables can be related to each other. The place to start learning about it is in the documentation.
Using inheritance, you would have a parent table called questions which defines questionId and other related columns. Then you can define multiple other tables such as matchingPairsQuestions which inherit from questions. Queries and foreign keys can then refer either to the individual "children" tables or to all of them as a single set.

Mysql errno 150 trying to create table with foreign key references

I'm trying to create a table in mysql with a foreign key reference, like this:
In database A:
CREATE TABLE replication (
id varchar(255) NOT NULL PRIMARY KEY,
uid varchar(255) NOT NULL,
value int(11) NOT NULL,
FOREIGN KEY (uid) REFERENCES databaseB.users(username)
);
In database B i have a table named users like this:
+-----------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+-------+
| id | varchar(255) | NO | | NULL | |
| username | varchar(255) | NO | PRI | NULL | |
+-----------------+--------------+------+-----+---------+-------+
When i try to create table replication, gives me the following error:
ERROR 1005 (HY000): Can't create table 'databaseA.replication' (errno: 150)
Any idea? Thanks in advance!
You need to add an index to uid or you will not be able to set it up to reference anything.
Also, typically in your DatabaseB you would have your users table have a Primary Key on ID and a unique index on username. Then you would set up a foreign key from DatabaseA.replication REFERENCES databaseB.users(id)
you cant make reference key with two different types
in databaseA is integer uid and databaseB is varchar
try this
FOREIGN KEY (uid) REFERENCES databaseB.users(id)
Are both databases of the same type (MyISAM, INNODB)? You cannot point a foreign key to a MyISAM DB.
This error can also occur when you are mixing types for the field type (which is the same in this case, varchar(255)), or when the encodings of the fields are different.
Another reason could be that you don't have access to the other database.
Thetype of the field in a foreign key must be the same as the type of the column they're referencing.I think this problem error because type of the field in a foreign key is different from the column they're referencing.
Your foreign key field is uid and referencing table your field is username.Here is the problem.Try to use same type of field in both table like
FOREIGN KEY (uid) REFERENCES databaseB.users(id)
Hope you understand and works for you.

MySQL Grouping rows by a shared ID

Say I have
ID | PRODUCT
1 | Apples
1 | Oranges
1 | Bananas
2 | Walnuts
2 | Almonds
3 | Steak
3 | Chicken
Is this possible to have this type of setup in MySQL? I created a test table, and made an ID column with primary index and auto incrementing. When I try to insert a couple rows all having the same ID, mysql returns an error.
Is this possible to do in mysql?
How did the duplicate records (ID) INSERTED when you set ID as Primary Key? Basically, it will not. Primary Keys are UNIQUE. If you want records to be like that, make another column which served as your primary key
CREATE TABLE sampleTable
(
ID INT NOT NULL AUTO_INCREMENT,
GROUP_ID INT NOT NULL,
PRODUCT VARCHAR(25),
CONSTRAINT pk_name PRIMARY KEY (ID),
CONSTRAINT uq_name UNIQUE (GROUP_ID, PRODUCT)
)
a UNIQUE constraint was added so to avoid duplicated rows.
That is possible, but it is not normalized as you have a repeating primary key. Primary keys must be unique, which means 1 can only occur once. If you have custom ID's for each product, then either use a compound primary key (id, product) or a surrogate key. A surrogate key would be an auto incrementing column that uniquely identifies the row. Your table would then look like this:
CREATE TABLE fruits (
auto_id int AUTO_INCREMENT PRIMARY KEY,
id int,
product varchar(15))
You mustn't create a primary key for the ID column, as this implies that it's unique.
Just take a normal index for your example.
On the other hand, in most cases, it makes sense to have a primary key, so I'd recommend adding a 3rd row (GENRE?) with a normal INDEX on it and leaving the primary key as it is.
When inserting data, just insert the GENRE and the PRODUCT, the ID will be automatically filled.

Multiple Primary/Foreign Keys

I'm going to be honest, I'm a bit hazy on how primary and foreign keys work. I was told to setup my database by someone on here so that I had 7 tables, one for organizations, one for categories, services, and cultures, and three cross reference tables between organization on one hand, and categories, services and cultures on the other.
Take the org_culture_xref table, for instance. I have two columns, one is org_id, which is the same as the org_id column (primary key) of the organization table. The other is cult_id, which is the same as the cult_id column (primary key) of the culture table.
I believe both of the columns of the org_culture_xref table are primary and foreign keys. However, this doesn't seem to allow me to have multiple values for both of these columns. I want to be able to have several relationships between organizations and cultures - as in every organization can be associated with multiple cultures and every culture can be associated with multiple organizations.
How do I ensure that I can have multiple values for both columns?
What you're talking about is a Many-To-Many relationship. You're on the right path using a cross-reference table.
It's good to review how foreign and primary keys work; there can only be one primary key per table, but there can be multiple foreign keys. However, note that a primary key doesn't have to be limited to one column; you can have a primary key that spans two, three, or more columns.
Your solution here is to have two foreign key, one for each column/table relationship, and one primary key that spans across both tables.
Here's an example of a table I used at one time, which links cities and counties in a many-to-many relationship.
mysql> show create table xref_cities_counties\G
*************************** 1. row ***************************
Table: xref_cities_counties
Create Table: CREATE TABLE `xref_cities_counties` (
`city_id` int(10) unsigned NOT NULL,
`county_id` tinyint(3) unsigned NOT NULL,
PRIMARY KEY (`city_id`,`county_id`),
KEY `city_id` (`city_id`),
KEY `county_id` (`county_id`),
CONSTRAINT `fk_xrefcitiescounties_cityid` FOREIGN KEY (`city_id`) REFERENCES `florida_cities` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_xrefcitiescounties_countyid` FOREIGN KEY (`county_id`) REFERENCES `florida_counties` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql>
mysql>
mysql> describe xref_cities_counties;
+-----------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| city_id | int(10) unsigned | NO | PRI | | |
| county_id | tinyint(3) unsigned | NO | PRI | | |
+-----------+---------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql>
I'd suggest some extra reading on the topic. It seems like you're on a good start.
The primary key for your cross ref table will be both of the columns, meaning that the combination of two ids must be unique but you can have repeats of individiual ids in either column.
Here is a statement to create such a table:
CREATE TABLE `x` (
`a_id` varchar(6) NOT NULL default '',
`b_id` varchar(6) NOT NULL default '',
PRIMARY KEY (`a_id`,`b_id`)
)
The issue itself and the cross ref table approach to many-to-many relationships applies to most (if not all) relational databases, but since I haven't used mysql in around 10 years I got that code from here, which seems to have a detailed discussion of the topic with mysql specific code.
Each column of org_culture_xref is a foreign key: org_id is a foreign key to organization, and cult_id is a foreign key to culture. The two of them together are the primary key of org_culture_xref.
So, something along these lines:
CREATE TABLE org_culture_xref
(
org_id NUMERIC(10) NOT NULL,
cult_id NUMERIC(10) NOT NULL,
PRIMARY KEY (org_id, cult_id),
FOREIGN KEY (org_id) REFERENCES organization (org_id),
FOREIGN KEY (cult_id) REFERENCES culture (cult_id)
);