I was wondering if you can specify the order in which table definitions and data fixtures are loaded using the CLI. My problem is that I have two tables, each having a foreign key constraint pointing to the other, so one of the constraints needs to be added after a record has been added. Or maybe there's a better way of doing this...I'm no db expert and my head is fuzzy today.
Schema:
CREATE TABLE clients (
id INT AUTO_INCREMENT,
name VARCHAR(255), address VARCHAR(255),
primary_contact_user_id INT # References a user record in the users table
...
);
CREATE TABLE users (
id INT AUTO_INCREMENT,
username VARCHAR(255),
client_id INT # References a client record in the clients table
...
);
ALTER TABLE clients
ADD CONSTRAINT clients_primary_contact_user_id_users_id
FOREIGN KEY (primary_contact_user_id) REFERENCES users(id);
ALTER TABLE users
ADD CONSTRAINT users_client_id_clients_id
FOREIGN KEY (client_id) REFERENCES clients(id);
I'm also not a DB expert, but I do spend a lot of time working with them. I believe the circular reference is actually incorrect.
Regardless of whether DB theory sanctions it or not, you could get one field though a join to another table, so it is an unnecessary circular reference. I'd suggest that you eliminate one and alter any queries to reflect this change.
Based on a guess, I'd suggest that you eliminate primary_contact_user_id, as that almost sounds like a possible many-to-many relationship where a single item is elected as "primary"...
If you feel this design is necessary, can you please explain why?
put the INSERT statements between the CREATE TABLE and ALTER TABLE statements.
Related
First of all, I'm from Spain so I'm sorry if I made some mistakes writing. So, I have two problems. It will be better if I give context before. I am not even junior, still learning code, and I thought that it will be a good proyect to create a web page where you can add ingredients, foods with that ingredients, etc. So I decided to start learning PHP and SQL. Now I'm trying to create a database, starting with some ingredients and two kinds of rices. My 1st problem is that I don't know if I need to create a data base for that. The second and main one is that I don't have any idea about how to get this working as I want.
See, First of all I created the table for ingredients´
CREATE TABLE ingredientes(
id int(255) auto_increment not null,
ingrediente varchar(255) not null,
CONSTRAINT pk_ingredientes PRIMARY KEY(id) )ENGINE=InnoDb;
Sorry 'cause it's on spanish :/, but nothing to hard to understand.
So I add some ingredients.
Here the pic showing them
After that I created two tables, and add ingredients to them.
CREATE TABLE arroz_con_pollo(
id int(255) auto_increment not null,
ingrediente int(255) not null,
CONSTRAINT pk_arroz_con_pollo PRIMARY KEY(id),
CONSTRAINT fk_pollo_ingredientes FOREIGN KEY(ingrediente) REFERENCES ingredientes(id) )ENGINE=InnoDb;
CREATE TABLE arroz_cubana(
id int(255) auto_increment not null,
ingrediente int(255) not null,
CONSTRAINT pk_arroz_cubana PRIMARY KEY(id),
CONSTRAINT fk_cubana_ingredientes FOREIGN KEY(ingrediente) REFERENCES ingredientes(id))ENGINE=InnoDb;
Here the picture showing the ID's.
Here
So now I spend a lot of time researching and find out that I can show the names by using this command
SELECT a.id,i.ingrediente
FROM ingredientes i, arroz_cubana a
WHERE i.id = a.id;
And have something like this
At this point, everything is, more or less, working. My issue came when I want to create a data base that keep all the names (arroz con pollo, arroz cubana...) in an only table named as 'rices' to be able to choose a name, and automatically have the ingredients there, without any complication for the user. But, I literally have no idea. I've been coding for hours without any victory on that. And I haven't see anything similar on the web so, if someone tell me how to fix that issue or how to make that idea of a web to keep ingredients and foods, I'll be very greatful.
Your data structure is messed up. SQL is not designed to have a separate table for each ingredient. Instead, you want two other tables.
The first is for dishes:
CREATE TABLE dishes (
dish_id int auto_increment not null,
name varchar(255)
);
You would then insert appropriate rows into this:
INSERT INTO dishes (name)
VALUES ('arroz_on_pollo');
Then you have another table for the ingredients:
CREATE TABLE dishes_ingredients (
dish_ingredient_id int auto_increment primary key,
dish_id int not null
ingredient_id int not null,
CONSTRAINT fk_dish_ingredientes_dish FOREIGN KEY(dish_id) REFERENCES dishes(dish_id)
CONSTRAINT fk_dish_ingredientes_dish FOREIGN KEY(ingredient_id) REFERENCES ingredientes(ingredient_id)
);
Voila! New dishes are just rows in a table, so you can get the names using a SELECT.
Notes on structure:
int(255) really makes no sense. Just use int. The number in parentheses is a width for the value when printing it and 255 is a ridiculous width.
I am a fan of naming primary keys with the table name. That way, the primary key and foreign key typically have the same name.
You should not have a table per dish. Create one table "dish", that includes a column "name". Each row represents a dish. Then create a supporting table where you list the (multiple) ingredients for each dish. Look around for a tutorial on databases, this topic is too large to explain in a stackoverflow question (or several).
And so you do not need to be able to list the table names, the way you were considering. (Which is not something SQL supports directly; different databases provide non-standard ways to do it, but as explained you do not actually need such a feature.)
i have three tabs in my Db:
1.pers_info(id(primary), name ,....)
2.contacts(c_id(primary), phone, email, ...)
now 1 person can have multiple rows in contacts tab.
thus to minimize redundancy i made another tab contact_relation(id (foregin key references pers_info(id), c_id (foregin key references contacts(c_id))
i successfully created the relation and also was able to insert apt entries(related id and c_id) to it "using last_insert_id();" to extract id and c_id required.
now the problem..
i dropped tab contacts_rel. and created it this way :
CREATE TABLE contacts_relation (
id INT NOT NULL,
cid INT NOT NULL,
FOREIGN KEY (id)
REFERENCES pers_info(id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (c_id)
REFERENCES contacts(c_id)
);
if now i try to insert into tab cont_rel, it gives error :
cannot add or update a child row foreign key constraint fails.
which makes sense..
i was hoping that adding constraints in the defn of tab cont_rel would save the hassle of inserting entries in it manually using "last_insert_id();"
so is there a way, i could maintain ref integrity with new data
coming.. thanks.
Why the third table? When you many to many relation you need intermediate table. You have one to many relation so two tables are sufficient. Table contacts need FK to table pers_info. Add it if you don't have already.
Here's a simple transaction example with LAST_INSERT_ID(): SQL INSERT INTO multiple tables
Some info about foreign keys and altering table:
Add Foreign Key to existing table
http://dev.mysql.com/doc/refman/5.0/en/alter-table.html
I've got a friendship table between users that looks like this.
CREATE TABLE user_relations (
pkUser1 INTEGER UNSIGNED NOT NULL,
pkUser2 INTEGER UNSIGNED NOT NULL,
pkRelationsType TINYINT UNSIGNED NOT NULL,
PRIMARY KEY(pkUser1,pkUser2),
FOREIGN KEY(pkuser1) references users(ID),
FOREIGN KEY(pkuser2) references users(ID),
FOREIGN KEY(pkRelationsType) references user_relations_type(ID)
);
pkRelationsType is a pointer to another table that defines the kind of relation the users have (friendship(1),pending(2) or blocked(3))
If user 1 is friend with user 2 I've got only one instance |1|2|1| and NOT also |2|1|1|.
The thing is, in order to block a user I have to keep in mind the relation can be already made (users can be already friends or even have the pending friendship petition) so I am trying to insert the data or update it if the relation does not exist already.
I have this for the friendship request send, but this just ignores the the insert if the data exists already.
INSERT INTO
user_relations(pkUser1,pkUser2,pkRelationsType)
SELECT * FROM (SELECT :sender0,:target0,2) AS tmp
WHERE NOT EXISTS
(SELECT pkUser1 FROM user_relations
WHERE
(pkUser1= :sender1 AND pkUser2=:target1) OR (pkUser1=:sender2 AND pkUser1=:target2) LIMIT 1)
Due to the nature of the table I cannot use INSERT ... ON DUPLICATE KEY UPDATE.
I've been thinking about handling it with PHP, searching for the relation and it's order if exists and then doing one thing or another but it seems like a waste of processing.
Please note that I'm not a MYSQL expert even though I've handled myself so far.
Hope I have explained myself well enough.
Thanks for the feedback.
From your description, it seems that you are only keeping the "latest" relationship. If this is the case, why don't you DELETE the relationship first, then INSERT the new one?
I have an InnoDB MySQL database with a table that needs to be able to connect to one of 26 other tables via a foreign key. Each record will only connect to one of these 26 at a time. The table will probably consist of no more than 10,000 records. Is there an alternative way to do this?
-- -----------------------------------------------------
-- Table `db_mydb`.`tb_job`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `db_mydb`.`tb_job` (
`job_id` INT(11) NOT NULL AUTO_INCREMENT ,
// Removed 26 other fields that the table requires
`job_foreignkey_a_id` INT(11) NULL DEFAULT NULL ,
`job_foreignkey_b_id` INT(11) NULL DEFAULT NULL ,
`job_foreignkey_c_id` INT(11) NULL DEFAULT NULL ,
// Removed the other 23 foreign keys fields that are the same
PRIMARY KEY (`job_id`) ,
CONSTRAINT `fka_tb_job_tb`
FOREIGN KEY (`job_foreignkey_a_id` )
REFERENCES `db_mydb`.`tb_foreignkey_a` (`foreignkey_a_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fkb_tb_job_tb`
FOREIGN KEY (`job_foreignkey_b_id` )
REFERENCES `db_mydb`.`tb_foreignkey_b` (`foreignkey_b_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fkc_tb_job_tb`
FOREIGN KEY (`job_foreignkey_c_id` )
REFERENCES `db_mydb`.`tb_foreignkey_c` (`foreignkey_c_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
// Removed the other 23 foreign keys constraints that are the same
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
CREATE INDEX `fka_tb_job_tb` ON `db_mydb`.`tb_job` (`job_foreignkey_a_id` ASC) ;
CREATE INDEX `fkb_tb_job_tb` ON `db_mydb`.`tb_job` (`job_foreignkey_b_id` ASC) ;
CREATE INDEX `fkc_tb_job_tb` ON `db_mydb`.`tb_job` (`job_foreignkey_c_id` ASC) ;
// Removed the other 23 foreign keys indexes that are the same
This is the problem of generic foreign keys, which MySQL and friends tend not to support. There are two ways you can do this.
The first, as you have done, is nullable foreign keys, one for every type.
The other, as in Django's Content Types, is to have a join table, each row having a row id and a field that specifies the table to look up on. Your code then has to formulate the SQL query depending on the contents of the field. It works well, but has limitations:
The downside of the first one is bloat, but it brings you the upsides of normal FKs, i.e. referential integrity and SQL joins etc, both of which are very valuable. You can't get those with the second method.
Depends if you want to maintain foreign key constraint, you can have one table that references one of the tables by a key or table type. Problem is you will loose the foreign key constraint. Of course, if you can create a function based constraint, then it can work for you. Or you can enforce the relationship using a trigger. Function based constraints are not available in mysql.
Yes, you can do that. These two StackOverflow answers illustrate the underlying principles in a slightly different context.
Same data from different entities in Database - Best Practice - Phone numbers example
Different user types / objects own content in same table - how?
Using MySQL, you'll need to replace critical CHECK() constraints with foreign key references. This doesn't work in the most general case for MySQL, but it does work in this particular application.
If this isn't enough information to get you going, leave me a comment, and I'll try to expand this answer a little more.
I'm trying to create some tables in a mysql db to handle customers, assign them to groups and give customers within these groups unique promotion codes/coupons.
there are 3 parent(?) tables - customers, groups, promotions
then I have table - customerGroups to assign each customer_id to many group_id's
also I have - customerPromotions to assign each customer_id to many promotion_id's
I know I need to use cascade on delete and update so that when I delete a customer, promotion or group the data is also removed from the child tables. I put together some php to create the tables easily http://pastebin.com/gxhW1PGL
I've been trying to read up on cascade, foreign key references but I think I learn better by trying to do things then learning why they work. Can anyone please give me their input on what I should do to these tables to have them function correctly.
I would like to have the database and tables set up correctly before I start with queries or anything further so any advice would be great.
You seem to want just a little guidance. So I'll try to be brief.
$sql = "CREATE TABLE customerGroups (
customer_id int(11) NOT NULL,
group_id int(11) NOT NULL,
PRIMARY KEY (customer_id, group_id),
CONSTRAINT customers_customergroups_fk
FOREIGN KEY (customer_id)
REFERENCES customers (customer_id)
ON DELETE CASCADE,
CONSTRAINT groups_customergroups_fk
FOREIGN KEY (group_id)
REFERENCES groups (group_id)
ON DELETE CASCADE
)ENGINE = INNODB;";
You only need id numbers when identity is hard to nail down. When you're dealing with people, identity is hard to nail down. There are lots of people named "John Smith".
But you're dealing with two things that have already been identified. (And identified with id numbers, of all things.)
Cascading deletes makes sense. It's relatively rare to cascade updates on id numbers; they're presumed to never change. (The main reason Oracle DBAs insist that primary keys must always be ID numbers, and that they must never change is because Oracle can't cascade updates.) If, later, some id numbers need to change for whatever reason, you can alter the table to include ON UPDATE CASCADE.
$sql = "CREATE TABLE groups
(
group_id int(11) NOT NULL AUTO_INCREMENT,
group_title varchar(50) NOT NULL UNIQUE,
group_desc varchar(140),
PRIMARY KEY (group_id)
)ENGINE = INNODB;";
Note the additional unique constraint on group_title. You don't want to allow anything like this (below) in your database.
group_id group_title
--
1 First group
2 First group
3 First group
...
9384 First group
You'll want to carry those kinds of changes through all your tables. (Except, perhaps, your table of customers.)