How to normalize my tables? - mysql

I'm in a situation here. I want to normalize my table:
Exam_Papers
ID Country_Code Level
1 UK 1
2 UK 2
3 UK 3
4 UK 4
5 UK 5
6 UK 6
7 UK 7
8 SA 1
9 SA 2
10 SA 3
11 SA 4
12 SA 5
13 SA 6
14 SA 7
15 IN 1
16 IN 2
I understand that I could normalize this by putting Levels in a separate table, but then Country_Code would still contain duplicated data, so how normalized should this table be?
Such normalized that Country_Code and Level have their own table?
Also, in this example how is normalization beneficial because either way, making 2 separate tables would mean the FK's would still be duplicated (for example if UK had the ID of 1, my table would contain 7 1's)
Thanks in advance

You don't need to make two tables in this case. Because as you mentioned you will still require the entry (may be in their id format). Also, I feel if you do it the other way, your performance would degrade in terms of SQL queries.

Related

tree privileges database design

I'm unsure into how to ask this so i will try to illustrate with an example.
What i am trying to achieve is an application that will be able to discern different levels of privileges. and i can't figure out how my database and queries should be made.
there are this levels of user:
Director
Manager
Executive
So a column in my user table will be a privilege INT to know what type of user, and another column will be Parent user, since x amount of Executives will be assigned to a manager, and x amount of managers will be assigned to a Director.
Example table USERS:
ID username privilege parent
1 Director1 1 null
2 Director2 1 null
3 Manager1 2 1
4 Manager2 2 1
5 Manager3 2 2
6 Executive1 3 3
7 Executive2 3 3
8 Executive3 3 4
9 Executive4 3 4
10 Executive5 3 5
11 Executive6 3 5
And they will have their "costumers".
Example table COSTUMERS
ID name seller
1 c1 11
2 c2 10
3 c3 10
4 c4 9
5 c5 8
6 c6 7
7 c7 6
8 c8 5
9 c9 4
10 c10 3
11 c11 2
12 c12 1
so if an Executive went into the app it would only be able to see their own costumers.
but if a manager went in he would be able to see his costumers and also from the executives assigned to him. and the same happens to the directors.
Is this the right way to make it? if so what would be the best approach to an effective query?
example diagram( you can see the organization diagram and each of the costmer every user has.
for example if users was to check his costumers he should see:
Director1: C12,C10,C9,C7,C6,C5,C4
Director2: C11,C8,C3,C2,C1
Manager1: C10,C7,C6
Manager2: C9,C5,C4
Manager3: C8,C3,C2,C1
and the executives only would see their own costumers.

How can i convert a comma separated columns into junction table?

I am pretty new to mysql and this site. I got an old mysql database (100.000 entries) to migrate to our new system. This is the old table:
CUSTOMER
Customer_ID Name Categories
1 Bob 1,2
2 Phil NULL
3 Ines 10,8
4 Carol 1
5 Rick 13,2
And i need the following structure:
CUSTOMER
Customer_ID Name
1 Bob
2 Phil
3 Ines
4 Carol
5 Rick
Category
Category_ID Category_Name
1 Biker
2 Doctors
3 Teacher
... ...
13 Drivers
CustomerHasCategory
Customer_ID Category_ID
1 1
1 2
3 10
3 8
4 1
5 13
5 2
Thanks for any help.
I also had this problem but not in MySQL. I solved it with Python using the Pandas library. So, the exact steps I followed won't be useful for you. However, I'll show you the general idea behind the solution I used.
Below is image of the original column
First, I splitted the text into columns using the comas as the delimiter.
Next, I 'stacked' the columns
Finally, I removed the artefact column(s). So, I have only the ID and the values columns. This creates a one-to-many relationship.

Edit product selling location using mysql

I'm building a e-Commerce platform (PHP + MySQL) and I want to add a attribute (feature) to products, the ability to specify (enable/disable) the selling status for specific city.
Here are simplified tables:
cities
id name
==========
1 Roma
2 Berlin
3 Paris
4 London
products
id name cities
==================
1 TV 1,2,4
2 Phone 1,3,4
3 Book 1,2,3,4
4 Guitar 3
In this simple example is easy to query (using FIND_IN_SET or LIKE) to check the availability of product for specific city.
This is OK for 4 city in this example or even 100 cities but will be practical for a large number of cities and for very large number of products?
For better "performance" or better database design should I add another table to table to JOIN in query (productid, cityid, status) ?
availability
id productid cityid status
=============================
1 1 1 1
2 1 2 1
3 1 4 1
4 2 1 1
5 2 3 1
6 2 4 1
7 3 1 1
8 3 2 1
9 3 3 1
10 3 4 1
11 4 3 1
For better "performance" or better database design should I add
another table
YES definitely you should create another table to hold that information likewise you posted rather storing in , separated list which is against Normalization concept. Also, there is no way you can gain better performance when you try to JOIN and find out the details pf products available in which cities.
At any point in time if you want to get back a comma separated list like 1,2,4 of values then you can do a GROUP BY productid and use GROUP_CONCAT(cityid) to get the same.

Mysql query contains

Table
id name(varhcar)
2 15
3 15,23
4 1315,424
5 1512,2323
6 23,15,345
7 253,234,15
I need to find out those values which contains 15 which mean i need 2,3,6,7 not 4,5.
Above is sample data, in real time it can be any number.
Can anyone please help me?
If your database is small, consider using find_in_set function:
select * from your_table
where find_in_set('15',name);
Consider change the model to master-detail table to increase the speed if you have a big table.
This is the kind of relational model you could adopt to make this an easy problem to solve:
TABLE: records
id
2
3
4
5
6
7
TABLE: values
record_id value
2 15
3 15
3 23
4 1315
4 424
5 1512
5 2323
6 23
6 15
6 345
7 253
7 234
7 15
Then you can query:
SELECT DISTINCT id FROM records
INNER JOIN values ON records.id = values.record_id AND values.value = 15
This is the only way you can take good advantage of MySQL's query optimizer.
Not that it's impossible to do what you're trying to do, but it kind of misses the point.
If you're already storing data in this format, you should write a one-time migration to transfer it to this "normalized" format in the programming language of your choice, using something like Java's split or PHP's explode.

Storing data in a link table

Supoose I have the following:
tbl_options
===========
id name
1 experience
2 languages
3 hourly_rate
tbl_option_attributes
=====================
id option_id name value
1 1 beginner 1
2 1 advanced 2
3 2 english 1
4 2 french 2
5 2 spanish 3
6 3 £10 p/h 10
7 3 £20 p/h 20
tbl_user_options
================
user_id option_id value
1 1 2
1 2 1
1 2 2
1 2 3
1 3 20
In the above example tbl_user_options stores option data for the user. We can store multiple entries for some options.
Now I wish to extend this, i.e. for "languages" I want the user to be able to specify their proficiency in a language (basic/intermediate/advanced). There will also be other fields that will have extended attributes.
So my question is, can these extended attributes be stored in the same table (tbl_user_options) or do I need to create more tables? Obviously if I put in a field "language_proficiency" it won't apply to the other fields. But this way I only have one user options table to manage. What do you think?
EDIT: This is what I propose
tbl_user_options
================
user_id option_id value lang_prof
1 1 2 null
1 2 1 2
1 2 2 3
1 2 3 3
1 3 20 null
My gut instinct would be to split the User/Language/Proficiency relationship out into its own tables. Even if you kept it in the same table with your other options, you'd need to write special code to handle the language case, so you might as well use a new table structure.
Unless your data model is in constant flux, I would rather have tbl_languages and tabl_user_languages tables to store those types of data:
tbl_languages
================
lang_id name
1 English
2 French
3 Spanish
tbl_user_languages
================
user_id lang_id proficiency hourly_rate
1 1 1 20
1 2 2 10
2 2 1 15
2 2 3 20
3 3 2 10
Designing a system that is "too generic" is a Turing tarpit trap for a relational SQL database. A document-based database is better suited to arbitrary key-value stores.
Excepting certain optimisations, your database model should match your domain model as closely as possible to minimise the object-relational impedance mismatch.
This design lets you display a sensible table of user language proficiencies and hourly rates with only two inner joins:
SELECT
ul.user_id,
u.name,
l.name,
ul.proficiency,
ul.hourly_rate
FROM tbl_user_languages ul
INNER JOIN tbl_languages l
ON l.lang_id = ul.lang_id
INNER JOIN tbl_users u
ON u.user_id = ul.user_id
ORDER BY
l.name, u.hour
Optionally you can split out a list of language proficiencies into a tbl_profiencies table, where 1 == Beginner, 2 == Advanced, 3 == Expert and join it onto tbl_user_languages.
i'm thinking it's a mistake to put "languages" as an option. while reading your text it seems to me that english is an option, and it might have an attribute from option_attributes.