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.)
Related
I am extending a product sales plugin and am trying to understand how wordpress handles database relations. I am building tables on activation using dbDelta. An example of a table schema would be:
$table_schema = [
"CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}plugin_orders` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`people_id` bigint(20) DEFAULT NULL,
`order_id` bigint(20) DEFAULT NULL,
`order_status` varchar(11) DEFAULT NULL,
`order_date` datetime DEFAULT NULL,
`order_total` decimal(13,2) DEFAULT NULL,
`accounting` tinyint(4) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `people_id` (`people_id`),
KEY `order_id` (`order_id`)
) $collate;",
"CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}plugin_order_product` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`order_id` bigint(20) DEFAULT NULL,
`product_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `order_id` (`order_id`),
KEY `product_id` (`product_id`)
) $collate;"
];
I see that id in each table is the PRIMARY KEY but what does declaring the other KEYs actually do? I have read that wordpress uses MyISAM which doesn't actually build foreign key connections. While these tables may point to other tables already existing, in this example does declaring KEY order_id (order_id) create a variable of sorts called order_id that any other table can use to reference? Is this code specifically connecting one tables attributes to another tables attributes (it doesn't appear to be)? After these tables are built, I can inspect them in phpMyAdmin and see that there are indexes assigned but no foreign key constraints. How does this code create tables that point one table at another to build relations?
KEY `foo_bar` (`order_id`)
"KEY" is the same as "INDEX". It specifies that a separate data structure is maintained for the efficient access of the table via the column order_id.
foo_bar is the name of the index. It has no special meaning, and has very few uses. For example, DROP KEY foo_bar; is the way to get rid of the index.
In MyISAM, a "FOREIGN KEY" allowed, but ignored. In InnoDB, it does two things:
Create an index if one is not already provided
Provide a constraint. The default effectively "complain if the other table does not already have the value referenced".
Having an index is important for performance. The index above make this
SELECT ... WHERE order_id = 1234 ...
run in milliseconds, even if there are billions of rows in the table. Without the index, the query would take minutes or hours.
A PRIMARY KEY is a UNIQUE key, which is an INDEX.
UNIQUE(widget) says that only one row can have a particular value of `widget in the table.
PRIMARY KEY(id) says that each row is uniquely identified by the column id. InnoDB really wants each table to have a PK.
"id" is a convention (not a requirement) for the name of the PK. It is also INT AUTO_INCREMENT by convention. You may or may not actually ever touch id.
Tables can be related to each other in 3 main ways:
1:1 -- They share the same unique key. This is rarely useful; you may as well have a single table.
1:many -- An "order" has several "items" in it (one-order : many-items). This is usually handled by order_id being a column in the items table.
many:many -- students_classes -- each student is in many classes; each class has many students. This is implemented via a mapping table that has (usually) only two columns: student_id and class_id (no id is needed) and PRIMARY KEY(student_id, class_id) and INDEX(class_id, student_id). Those two indexes make it efficient to go from a known student to their classes, and vice versa.
Another convention for the PK of a table is to include the table name. (It is clutter to do that for other columns, such as order_status.) I was assuming this convention for student_id and class_id.
But now I am confused by your plugin_orders -- it has both id and order_id. If that table describes "orders", then I would expect order_id to be the PK instead of id.
And, if order_product is a list of all the "products" in each "order", then I would expect you to have the 1:many pattern.
What indexes to have?
PRIMARY KEY to uniquely identify each row -- either id or some column (or combination of columns) that are unique.
Other columns, as needed, for the SELECTs, UPDATEs, and DELETEs that you have. Do not blindly add indexes before having some clues of the queries that might need them.
Indexes sometimes help in sorting:
SELECT ... ORDER BY last_name, first_name;
together with
INDEX(last_name, first_name)
Indexes provide performance; FKs provide integrity checks. Neither is "required"; both are "desirable".
MyISAM is ancient; you should change to InnoDB.
Then do something like
SELECT ...
FROM plugin_orders AS o
JOIN plugin_order_product AS op
ON o.order_id = op.order_id
WHERE ...
In this example, the Optimizer will perform the query something like this:
Look at the WHERE to see which table is best filtered by the conditions there. Declare that to be the first table work with.
Scan through the first table, using an index if practical.
For each row in the first table, reach into the second table.
Reaching into the second table would probably be done via INDEX(order_id) on the second table. This would make the JOIN fast and efficient.
Both tables have INDEX(order_id), but that is not relevant.
Next example:
SELECT ...
FROM plugin_orders AS o
JOIN plugin_order_product AS op
ON o.order_id = op.order_id
WHERE o.people_id = 123 -- note
Pick o as the first table due to filtering on people_id
use op INDEX(people_id) to rapidly find the o rows that are relevant.
etc (op is the second table)
Next example:
SELECT ...
FROM plugin_orders AS o
JOIN plugin_order_product AS op
ON o.order_id = op.order_id
WHERE op.product_id = 9887 -- changed again
Pick op as the first table due to filtering on product_id
use o INDEX(people_id) to rapidly find the op rows that are relevant.
etc (o is the second table this time)
Hello friends I am working on a school database system based on php mysql. the basic structure is as below:
Table Class-Details of all classes. Primary Key Class ID
Table Student-Details of all students, Primary key studentID. Foreign Key ClassID
Table Semester-Details of all Semesters, key SemesterID
Table class–Semester. This table solves many to many relation, primary key- IDs of both class and semester. Foreign Key ClassID, SemesterID
Table Subject -Details of all Subjects, key SubjectID
Table class–Subject. This table solves many to many relation, primary key- IDs of both class and semester. Foreign Key ClassID, SubjectID
Table marks- consists of student ID, Subject ID, Semester ID, Marks Achieved.Foreign Key ClassID, SemesterID, SubjectID
I have also applied foreign keys in all the tables which are referring back to the parent table. I am looking to apply integrity in my database so that a student for a particular class will automatically be assigned to subjects of that particular class.
If we try to change the subjects of the student, database should throw an error that these subjects belong to the class for which student is a part of.
I am sure this can be done using foreign key constraints. However, I am bit naive to do so. A working example is highly appreciated
ENGINE = InnoDB
AUTO_INCREMENT = 53
DEFAULT CHARACTER SET = utf8;
Ok, I'll try to help. :-) First make sure you know the syntax completely by using the MySQL Manual for creating tables.
MySQL 5.1: CREATE TABLE
Look for the sections that look like this.
reference_definition:
REFERENCES tbl_name (index_col_name,...)
[MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
[ON DELETE reference_option] <----
[ON UPDATE reference_option] <----
reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION
Here is an example (...attept ...) from a child table of contact statistics that links to a contacts (people) parent table.
CREATE TABLE IF NOT EXISTS contactStats_tbl(
id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Contact ID number.',
email VARCHAR(254) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT 'E-mail address from contacts_tbl.',
subscribeTime TIMESTAMP DEFAULT '0000-00-00 00:00:00' COMMENT 'Time of subscription.',
unsubscribeTime TIMESTAMP DEFAULT '0000-00-00 00:00:00' COMMENT 'Time of unsubscription.',
totalMessages INT(4) NOT NULL COMMENT 'Number of messages sent.',
newsLetter ENUM('Y', 'N') CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT 'N' COMMENT 'Newsletter subscription.',
CONSTRAINT csconstr01 FOREIGN KEY (id, email) REFERENCES contacts_db.contacts_tbl(id, email) ON UPDATE CASCADE ON DELETE RESTRICT)
ENGINE=InnoDB DEFAULT CHARACTER SET = utf8 COMMENT 'Contact statistics table.';
Essentially, with table constraints you are focusing on a time when someone attempts to DELETE or UPDATE a record in a child table containing fields that point to a parent table (foreign keys, in this case). For all of your child tables, my advice would be to set the ON DELETE options to RESTRICT (the default). But, for ON UPDATE, child tables should probably CASCADE to keep them consistent with their parents (I have not researched referential integrity for a while, but I think that's how it goes! Dang that MS Access! Don't vote me down if I am wrong. Just comment and I'll fix my answer. :-)). The best thing to do would be to make sure you know how referential integrity applies to the situation at hand. Truthfully, I forget how the ON UPDATE bit works because I have not used it in a while. :-)
Now, as far as automatically inserting field values into a record (in a secondary table) based on actively inserting a record into some other table (primary table), make sure that you are not in need of a trigger.
MySQL 5.1: CREATE TRIGGER
This should get you going. I tried! :-)
Anthony
I am working on a project where I want to allow the end user to basically add an unlimited amount of resources when creating a hardware device listing.
In this scenario, they can store both the quantity and types of hard-drives. The hard-drive types are already stored in a MySQL Database table with all of the potential options, so they have the options to set quantity, choose the drive type (from dropdown box), and add more entries as needed.
As I don't want to create a DB with "drive1amount", "drive1typeid", "drive2amount", "drive2typeid", and so on, what would be the best way to do this?
I've seen similar questions answered with a many-to-many link table, but can't think of how I could pull this off with that.
Something like this?
CREATE TABLE `hardware` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(256) NOT NULL,
`quantity` int(11) NOT NULL,
`hardware_type_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `type_id` (`hardware_type_id`),
CONSTRAINT `hardware_ibfk_1` FOREIGN KEY (`hardware_type_id`) REFERENCES `hardware_type` (`id`)
) ENGINE=InnoDB
hardware_type_id is a foreign key to your existing table
This way the table doesnt care what kind of hardware it is
Your answer relies a bit on your long term goals with this project. If you want to posses a data repository which has profiles all different types of hardware devices with their specifications i suggest you maintain a hardware table of each different types of hardware. For example you will have a harddisk table which consist of all different models and types of hardisks out there. Then you can assign a record from this specific table to the host configuration table. You can build the dataset as you go from the input from user.
If this is not clear to you let me know i will create a diagram and upload for you.
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.)
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.