MySQL Multiple references between tables - mysql

This question is probably quite easy to answer, but since I haven't got much experience in database design, I'm stuck. I don't even know how to google this because I don't know the terminology ....
I have a mysql database with two tables and in the first table i need to make MULTIPLE references to the second table. What should I use? Can I select multiple matches with Enum? Or should I just use a comma separated list and varchar?
|MAIN TABLE
|==========================================
| id (primary index)
| date (tstamp)
| product name (varchar)
| componentids (int, enum, varchar ???)
|===========================================
|COMPONENTS TABLE
|===========================================
| componentid (int)
| name (varchar)
| info (varchar)
|===========================================
so a possible scenario would be this:
|MAIN TABLE
|=====================================================
| id | 1 | 2 |
| date | 34958734958 | 349587123138 |
| product name | A test product | A second product |
| componentids | 2,3 | 1,2 |
|=====================================================
|COMPONENTS TABLE
|========================================================
| componentid | 1 | 2 | 3 |
| name | Component 1 | Component 2 | Component 1 |
| info | info. text | info. text | info. text |
|========================================================
how do I achieve this in an effective way?
thank you very much for your help!

What you're after is a many-to-many relationship. Each component can belong to multiple products, and each product can have multiple components. I'd strongly recommend using a third table for this, maybe called product_components.
Your main table has (id, date, name)
Your components table has (id, name, info)
Your product_components table has (product_id, component_id). Each of these is a foreign key that references the main table and component table respectively.
This maintains "referential integrity" which means that it becomes impossible to have a product referring to a component that doesn't exist (e.g. the database will throw an error if you try).
And yes, you can select the multiple components associated with one product in one go this way.
SELECT components.*
FROM components
JOIN product_components
ON components.id = product_components.component_id
WHERE product_components.product_id = <some product id>

No comma-separated lists or varchar. That's not the relational way.
How should it go? Are there many rows in the main table for every one in component, or visa versa?
A one-to-many relationship means adding a foreign key to the many table and JOINing the two:
select *
from main
join component
on main.componentid = component.componentid
This will match all the rows in the main table with their component counterpart.

Related

Adding data to table by comparing one table to another

I am working to split apart this one large table into smaller tables for easier management via foreign keys, and have come across a dilemma with trying to bring the data back together. I am new to working with this type of data merging so I am a bit lost.
There are 3 tables: one table with a list of product owners, one table with a list of systems they are responsible for, and the original table with all of the data (examples below):
Product Owners Table:
+----+---------------+
| id | product_owner |
+----+---------------+
| 1 | User1 |
+----+---------------+
PRIMARY KEY: id
System Table:
+----+-----------+---------------+
| id | system | product_owner |
+----+-----------+---------------+
| 6 | Server1 | NULL |
+----+-----------+---------------+
FOREIGN KEY: product_owner(id)
Original Table:
+---------+---------------+
| system | product_owner |
+---------+---------------+
| Server1 | User1 |
+---------+---------------+
I want to take the data from the original table and merge it with the new system table, however I don't want to go the route of multiple UPDATE statements to add what needs to be added. What's the best route to approach on this?
After a bunch more poking around and reading additional terminology, I was able to solve my problem by using a mix of join statements in conjunction with update, set and where statements:
update system_table a
join original_table.system b
on a.system = b.system
join product_owner c
on c.product_owner = b.product_owner
set a.product_owner = c.id
where c.product_owner = b.product_owner;

How can i simulate a distribution of foreign keys to multiple similar tables?

I am about to create an application, that stores information about products. There is a big list of products(with ID, Name, ...) and they have to be distributed to some grocery stores, represented by tables, with equal columns.
students:
+-------------------------+
| student_ID | Name | ... |
| ... | ... | ... |
store_1
+-----------------------------+
| student_ID | inventory| ... |
| .. | ... | ... |
store_2
+-----------------------------+
| student_ID | inventory| ... |
| .. | ... | ... |
store_3
...
Is there a way to do this better (Without creating 1000 tables for 1000 stores)? I know i could put everything in one table, but if there are 1000s of stores with 1000s of products in each store (=> 1.000.000s of records in one table) it would probably take too long to query. I also thought about creating a json/csv-file for every location, but then there are problems like: How do i sort/query it as fast as in mysql? How can i do sth like 'on delete cascade', ...
Can anybody help me with a better solution/some ideas?
Three tables would do the trick: One for the products and all their attributes (Product_ID, description, vendor codes, etc.); a second table listing the stores (Store_ID, location, sales tax rate, manager, etc.); and finally a table to link the two with a compound primary key of Product_ID, Store_ID that has columns for inventory, price (if different by store, and any other store/product specific attributes).

Over 2500 tables in mysql

My application stores login information of over 2500 employees in a table named "emp_login".
Now I have to store the activities of every employee on daily basis. For this purpose i have created a separate table for every employee. E.g. emp00001, emp0002... Each table will have about 50 columns.
After digging in alot on stackoverflow I'm kind of confused. Many of the experts say that database having more than 200-300 tables on mysql is considered to be poorly designed.
My question is whether it is good idea to have such a bulk of tables? Is my database poorly designed? Should i choose other database like mssql? Or some alternative idea is there to handle the database of such applications??
Do -not- do it that way. Every employee should be in 1 table and have a primary key index ID ie:
1: Tom
2: Pete
You then assign the actions with a column that references the employees ID number
Action, EmployeeID
You should always group identical entities in a table with index ids and then link properties / actions to those entities by Id. Imagine what you would have to do to search a database that consisted of a different table for every employee. Would defeat the whole point of using SQL.
Event table could look like:
Punchin, 1, 2018/01/01 00:00
That would tell you Tom punched In at 2018/01/01 00:00. This is a very simple example, and you prob wouldn’t wanna structure an event table that way but it should get you on the right track.
This is nothing to do with MySQL but to do with your design which is flawed. You should have one table for all your employees. This contains information unique to the employees such as firstname, lastname and email address.
|ID | "John" | "Smith" | "john.smith#gmail.com" |
|1 | "James" | "Smith" | "james.smith#gmail.com" |
|2 | "jane" | "Jones" | "jane.jones.smith#yahoo.com" |
|3 | "Joanne" | "DiMaggio" | "jdimaggio#outlook.com" |
Note the ID column. Typicially this would be an integer with AUTO_INCREMENT set and you would make it the Primary Key. Then you get a new unique number every time you add a new user.
Now you have separate tables for every piece of RELATED data. E.g. the city they live in or their login time (which I'm guessing you want from the table name).
If it's a one to many relationship (i.e. each user has many login times), you create a single extra table which REFERENCES your first table. This is a DEPENDENT table. Like so:
| UserId | LoginTime |
| 1 | "10:00:04 13-09-2018" |
| 2 | "11:00:00 13-09-2018" |
| 3 | "11:29:07 14-09-2018" |
| 1 | "09:00:00 15-09-2018" |
| 2 | "10:00:00 15-09-2018" |
Now when you query your database you do a JOIN on the UserId field to connect the two tables. If it were only their LAST login time, then you could put it in the user table because it would be a single piece of data. But because they will have many login times, then login times needs to be its own table.
(N.b. I haven't put an ID column on this table but it's a good idea.)
If it's data that ISN'T unique to the each user, i.e. it's a MANY to MANY relationship, such as the city they live in, then you need two tables. One contains the cities and the other is an INTERMEDIARY table that joins the two. So as follows:
(city table)
| ID | City |
| 1 | "London" |
| 2 | "Paris" |
| 3 | "New York" |
(city-user table)
| UserID | CityID |
| 1 | 1 |
| 2 | 1 |
| 3 | 3 |
Then you would do two JOINS to connect all three tables and get which city each employee lived in. Again, I haven't added an ID field and PRIMARY KEY to the intermediary table because it isn't strictly necessary (you could create a unique composite key which is a different discussion) but it would be a good idea.
That's the basic thing you need to know. Always divide your data up by function. Do NOT divide it up by the data itself (i.e. table per user). The thing you want to look up right now is called "Database Normalization". Stick that into a search engine and read a good overview. It wont take long and will help you enormously.

MySQL link two tables together implicitly

Suppose we have two tables
A table called people with people linked to a bank account balances
| id | name | account_id |
--------------------------
| 1 | bob | 11 |
--------------------------
| 2 | sam | 22
A table called accounts with bank account balances
| id | value |
--------------
| 11 | 200 |
--------------
| 22 | 500 |
In order to link the two tables you can do
SELECT a.value as account_balance
FROM people p
WHERE p.name="bob"
LEFT JOIN accounts a ON p.account_id = a.id`
This would return
id => 1
name => bob
account_balance => 200
That's cool - but I am wondering if there is a more implicit way to do this via SQL linkage (foreign keys or otherwise). Can we in MySQL add links in some other way so that when we do a SELECT, it already knows to return value instead of **account_id **?
I'm asking this because I am creating a system where my users can create lookup tables and link them to other tables - but it must be do-able without any programming. The only other way I can think of is to set the name of account_id for example to accounts.value and treat that as a foreign key when doing a SELECT.
I would have to get the column structure and analyze and then determine that there is a foreign key and then return the appropriate foreign column by looking at the column name.

How do I relate one table to many different tables?

I have a list of tables i.e. student, teacher, staff, dept. and so on and each of these tables have comments specific to them. Now one record in a table can have one or many comments that shows it's a one to many relation from any table to comments table. I don't know what the best way is to relate comments table to each of these. If I put foreign key from comments table to each of these tables, it will be like 40-50 fields depending on no. of tables. Secondly if I add foreign key from each of these tables to remarks table, it will be like repeating whole row just for the second remarks foreign key? Similarly if I use just one field in each table as comments, I will be actually storing rows in just one text field. Any suggestions on how to achieve efficient solution?
Lets assume that your tables (student, teacher, staff, dept) all have a int primary key named Id.
For your comments table you could create a table.
Id int
CommentType enum (student, teacher, staff, dept)
LinkId int
Comment
A row in Comments might look like this
1,'Student',347,'text'
As this is a many-to-many relation, you migth might want to have a look at using an associative table.
Using your example, it might look something like this:
Your tables that can have comments:
+----------+------------+
| student | student_id |
+----------+------------+
| Steve | 12 |
| Larry | 57 |
| Sunshine | 88 |
+----------+------------+
+--------+---------+
| dept | dept_id |
+--------+---------+
| Math | 2 |
| P.E. | 5 |
| Drama | 12 |
+--------+---------+
Then you need to keep track of the actual comments:
+-----------------------+------------+
| comment | comment_id |
+-----------------------+------------+
| I love Math! | 3 |
| Larry is my hero... | 5 |
| Sunshine <3 Me! | 6 |
+-----------------------+------------+
Now, you need an association between these tables, this is where your associative table comes into play. You now associate what student or dept has what comments, like this:
+------------+------------+
| student_id | comment_id |
+------------+------------+
| 57 | 5 |
| 57 | 6 |
+------------+------------+
+---------+------------+
| dept_id | comment_id |
+---------+------------+
| 2 | 3 |
+---------+------------+
This is both effective and elegant. Give it a shot!
(And to save you another question perhaps)
You could of course use just one association table if you are concerned about having so many association tables, but I would advice against it since it is not as neat and removes some possibilities for referential integrity checks that you can have with the first solution:
+-----------+------------+---------+
| entity_id | comment_id | entity |
+-----------+------------+---------+
| 57 | 5 | student |
| 57 | 6 | student |
| 2 | 3 | dept |
+-----------+------------+---------+
(Which in turn should prompt you to add a lookup table for those entities... but let's not go there)
You could use intermediate "many-to-many" tables. Each base table (student, professor, etc.) would have an alter ego storing one foreign key to the base table (e.g. student_id) and one foreign key to the commments table. You practically double your number of tables but you don't need to modify existing tables and you get full flexibility.
If you want to keep the foreign-key constraint, you need to have a table that handles the mapping for each and every table that will have comment-childs.
Meaning, Comment will have a primary key, with a foreign key constraint to each and every table that handles the mapping.
then, in the mapping-table, you have comment_id and ????_id with a foreign key constraint to the approriate table.
Your comments table could look as follows:
CommentID (int) - Primary Key
TableName (varchar(250)) - Table the comment is related to
RecordID (int) - the ID of the record in the table referred to
Comment (text) - the actual comment
You could of course add optional fields like a timestamp, which would let you select comments in the order they were entered.
Now you can use this table to store comments for any table, and you can select them by filtering on table name and record ID.
is a student or teacher or staff not just a type of person..
so you have a person and a person can have many comments? so you have a personscomments table with a relation to that person and why have a remarks table..is a remark not just a type of comment..
its hard to see without a more in-depth schema
My 50 cents: Zoredache solution is definitely good, but I discourage usage of enums; they are not very smart in mysql: if you specify an unknown value, the error is represented with an empty string - even if some default is specified. Also, it's crazily long to ALTER if you want to modify or add a new type. unsigned tinyint should be enough for most of your needs ...