how to design this database - mysql

I have a table for users. Each user has certain skills they teach. So for example:
Bob can teach karate
Louise can teach piano and knitting
Roger can teach judo, sailing and fencing
This is how I've done it in the database:
Table users
pk: uid, name
1 Bob,
2 Louise,
3 Roger
Table skills
pk: sk_id, skill
1 karate,
2 piano,
3 knitting,
4 judo,
5 sailing,
6 fencing
Table user_skill (relationship between user and skills)
pk:usk_id, fk:uid, sk_id
1 1 1,
2 2 2,
3 2 3,
4 3 4,
5 3 5,
6 3 6,
I want to then display "Roger has these skills: judo, basketweaving"
select name, skill
from users, skills, user_skill
where users.uid = user_skill.uid
and users.uid = 3
Is this the right way to go about it - both in terms of designing the tables and querying (mysql)?
Then say I want to update their profile with the areas they teach in:
Bob can teach karate in London
Louise can teach piano in Bolton and knitting in Manchester
Roger can teach judo in London and Manchester, sailing in Liverpool and fencing in Bradford
So I add the following tables:
Table cities
pk: city_id, city
1 London,
2 Manchester,
3 Liverpool,
4 Bolton,
5 Bradford,
But I'm confused as to how to do the relationships. I keep writing it out and realizing it doesnt work and starting again so I've obviously gone wrong somewhere.

I would say your general DB structure is fine as far as the relations go. To incorporate the cities aspect you could use your proposed cities table, but also add a column to your user_skill table to include a reference to the city table.
Also make sure you use proper join statements in the select queries as this is best practice and helps the queries run as efficiently as possible.

Can users teach skills in more than one location, e.g. "bob teaches judo in london and bolton"? Or is it strictly one skill-one city?
Depending on how you want your tables, you'd either just add a 'city' field to the user_skills table, and have multiple "bob/judo/cityX" "bob/judo/cityY" type records. Or you'll add yet another table "user_city_skills" where it'd be "user_skill_ID, cityID".

Your Structure looks fine except your usr_skill table. To incorporate the last part add a fk city_id in user_skill table. If the player can teach the same skill in multiple cities, you will need an additional table to avoid multi-valued columns.

Yes, carry on with it. You should also add one more column in table user_skill which will hold city_id.

Related

SQL Architecture design for handling employee competencies

ninjas, I understand that this probably is a "way too broad" or "wrong portal" type question but SO feels like home, so I will give it a try anyways.
I have a table with employees
Table: employee
id, name
1 - John
2 - Jane
3 - Obama
4 - Donald
...nothing fancy. And then there is competencies table (a classifier of special tasks/responsibilieties)
competencies table:
id, name
1 - Janitor
2 - Sysadmin
3 - Programmer
4 - Pilot
...
Each employee can have multiple competencies (relations table)
table: employee_competency
id, employee_id, competency_id
1 - 1 - 1 - John is a Janitor
2 - 1 - 2 - John is also a Sysadmin (imagine that)
3 - 2 - 3 - Jane is a Programmer
4 - 3 - 3 - Obama is a Programmer
5 - 3 - 4 - ...and a Pilot
6 - 4 - 1 - Donald is a Janitor
The existencial problem of a database architecture or how to handle such cases.
I want to be able to define unlimited count of competencies and these competencies can vary from one customer to another (where the project I am programming will be installed - each project installation can have a different set of competencies)
In the code, I want to be able to select employees with specific competency (for example - list all employees who are Pilots)....
By hard-coding the competency ID when listing employees I loose ability to define competencies freely. I could define custom fields in the employee table like is_janitor, is_sysadmin, is_programmer, is_pilot, etc... but then I loose the ability to define unlimited count of competencies...
Is there a way to solve this rather XY problem with a different DB architecture approach?
The key idea here is that you have to have that list that allows you to pick a competency be data-driven as well. So, when you are on the screen/form/page where you are selecting the competency to list, you drive that selection by the table of competencies in the database, passing the ID of the competency as the Value of the selection back to your query so that you can query the list of employees by competency.
You should never put individual IDs into the system. Now, this gets complicated when you have behavior you want to drive based on the competency. This requires thinking at a higher level of abstraction. For example, lets say you have a form where you want to show another tab to allow the customer to select what planes a pilot is certified on. To drive this, I usually create flags that actually define the driving behaviors (like CAN_SELECT_PLANES) to add to a related table. This table defines the capabilities of the system, not the capabilities of the competency. It is important to maintain that abstraction because customers will want to vary their competency name, and you will find new uses for that feature later on.
To select all programmers from the database, use for example:
SELECT
e.name AS empl_name,
c.name AS comp_name
FROM
employee_competency ec,
competencies c,
employee e
WHERE
c.id=ec.competency_id
AND
e.id=ec.employee_id
AND
c.id=3

Database design - "Separate Tables Vs One table" for Select Queries

I have a MySQL table like following
Books Table
book-id category author author_place book_name book_price --------other 50 columns directly related to book-id
1 adventure tom USA skydiving 300
2 spiritual rom Germany what you are 500
3 adventure som India woo woo 700
4 education kom Italy boring 900
5 adventure lom Pak yo yo 90
.
.
4000 spiritual tom USA you are 10
As you can see there are around 4000 rows and around 55 columns, I am using this table mostly for select query, Maybe add or update new book after2-3 weeks
I have doubt about the category and author columns
now if I need to select the table by category and author, I can simply do
SELECT * from books Where author = 'tom'
Select * FROM books WHERE category='education'
It works fine, But according to standard database design I think I should separate the category and authors columns into separate tables (especially authors) and use their primary key as foreign key in the books table
Something like this
Books Table
book-id categ_id author_id book_name book_price --------other 50 columns directly related to book-id
1 1 1 skydiving 300
2 2 2 what you are 500
3 1 3 woo woo 700
4 3 4 boring 900
5 1 5 yo yo 90
.
.
4000 3 1 you are 10
Category Table
categ_id category_name
1 advernture
2 spiritual
3 education
. .
. .
30 something
Authors Table
author_id author country
1 tom USA
2 rom Germany
3 som India
4 kom Italy
5 lom Pak
But then I have to use join the tables each time I make a select query by authors or category, Which I think will be inefficient, Something like this
SELECT * FROM Books LEFT JOIN authors on authors.author_id = books.author_id WHERE books.author_id =1
SELECT * FROM Books LEFT JOIN categories on categories.categ_id = books.categ_id_id WHERE books.categ_id =1
So should I separate the first table into separate tables or first table design is better in this case?
This question has it's answer from Mr. Edgar F. Codd himself - the inventor of the relation model upon which all RDBMS are build.
Shortly after releasing the relational model papers he and his team followed with papers on the so called normal forms. There are few of them but the first 3 (at least) should be generally considered mandatory:
First normal form (1NF)
Second normal form (2NF)
Third normal form (3NF)
When you read them you'll see that your initial design is in violation of 2NF and you have come with a solution that more or less respects it. Go ahead with a the NF-compliant design without any doubts.
To elaborate a bit on your concerns with Join's performance. This is not an issue as long as the following criteria is met:
your database schema is well designed (2NF compliant at least)
you use Foreign keys to link the tables (MySQL's docs)
you join the tables by their FK
you have the hardware resources necessary to run your data
efficiently
e.g. on MySQL with InnoDB, on 2NF compliant schema using Foreign keys the join performance by the FK will be among the last things you'd ever be concerned.
Historically there was a DB engine in MySQL - the MyISAM - that did not support foreign key constraints. Perhaps it's the main source of feedback about poor join performance (along poor schema designs of course).

Is mysql database logic suitable for query?

I am designing a database, and I would like to know;
Can I answer this question with queries, how much skill employees earned from this trainings?
Is this a good structure to do it?
how much money spent per department
how much skill earned per employee
how much skill earned per department
id session_name Skill impact sugg dept function training_value training no
1 PHP Software 3 Sales 2 100usd 1
2 PHP Software 3 Finance 2 100usd 1
3 PHP communication 2 Sales 2 100usd 1
4 PHP communication 2 Finance 2 100usd 1
5 ASP Software 4 Sales 2 200usd 2
6 ASP Software 4 Finance 2 200usd 2
7 ASP database 1 Sales 2 200usd 2
8 ASP database 1 Finance 2 200usd 2
attended training table
id student_id training_no
1 1 1
1 1 2
student table
id name department
1 John 1
2 Mary 2
department table
id name
1 sales
2 finance
In the end I need to find skills for each student
john
software 7
communication 2
database 1
total spent
john 300 usd
total spent by department
sales 300 usd
Your schema looks OK to me.
You should, however, think about entities and relationships.
Your entities seem to be trainings, people, and departments.
You have a many:many relationship for people:trainings. That's good.
You have a one:many relationship for departments:people. That's also good.
It looks like you want some kind of relationship for trainings:departments. I'm guessing here, but you have a sugg dept column in your trainings table. Is that supposed to have a direct relationship to your departments table?
Do you actually need an extra entity called "attendance" rather than just a many-to-many relationship people:trainings. Do you want to record when a person did a training? Do you want to record how much that particular attendance cost? How about what marks they received if there was a quiz?
In that case, you'll want relationships where each person has zero or more attendances, each attendance has exactly one training, and each training has zero or more attendances.
My point: do the hard work of thinking through your entities and relationships, and the result will be a good design for your tables.
If I may put it another way: What part of the real world are you trying to capture in your data base? What's valuable in the real world that you want your data base to hold? In your application ...
Students are people. They are, umm, inherently valuable and persistent entities.
Trainings represent the labor and cost of creating them and presenting them.
Attendances represent the effort of students.
Departments probably pay the bill for attendances. They certainly represent power centers in your application.
What other items of value exist in this corner of the real world? Teachers? Managers? Venues (classrooms)? Equipment? Customers?
My point is, figure out your entities -- the items of value -- and the relationships between them. Then write your table definitions.

Database design for a tv series app

I'm developing a web application about TV shows. And i need help with the database design.
I made a list of what i need, but i can't figure out how to design it. I have the basic tables. Series, episodes, seasons etc. What i can't do is how to relate people with episodes/series. Here is my list:
There should be multiple people type. Actor/director/writer/guest etc.
I don't think creating seperate table for each type is a good idea. So there should be one people table. And i need to store the type somewhere.
A person may be in 1 or many series.
This can be done with people_serie table with foreign keys to people and series tables. But i need a way to relate a person to episodes too.
An actor may play 1 or many roles.
This can be done with person_role table.
This is where its getting complicating.
A role may be in 1 or many episodes in a serie.
A person may belong to more than one type in a serie. Ex: actor AND director
I hope i make it clear what the problem is.
Well, you're correct not to split the People table.
the first thing to do is add a Roles table, that will contain role id and role title (each column should be unique - you don't want 2 different ids for the Actor role...)
TblRoles
RoleId RoleTitle
-------------------
1 Director
2 Writer
3 Actor
Then you add a PersonToSeries table, that will hold it's own id, the person's id and the series's id.
This table will hold every person ever working on that series, being a regular staff member or a 1 episode guest.
TblPersonToSeries
PTSId PersonId SeriesId
---------------------------
1 1 1
2 3 8
3 4 7
The next table you will need is a PersonToEpisode table, that will hold the PersonToSeries id and the episode id, and the role id.
In this table you only need to keep integer ids so it's very light weight, and you will specify for each record in PersonToSeries the episodes it is relevant for.
TblPersonToEpisode
PTEPTSId RoleId
-------------------
1 2
2 3
3 1
When a person is usually the director of a series, but makes a guess appearance in an episode of that series, you can simply add 2 rows in PersonToEpisode for that PersonToEpisode with a different role id. (one for Actor and one for Director)
TblPersonToEpisode
PTEPTSId RoleId
-------------------
13 1
13 2

Searching for data that can be in two different column (query/design)

Sorry if the title is not clear. I am a bit confused about how to plan my database schema as given my database design skill level the requirement falls under kind of advanced :) I could really use some help here. Anyway, here it goes ...
I need to track match details for teams. For the sake of simplicity, lets say I need to track the match date, result and the teams that played the match. Now, how do I design my tables so I can make sure all relevant data is returned without having to keep multiple records of the same match. I am not sure if I am explaining clearly, so here's an example below.
match_id team1 team2 result
________ ________ ________ ________
1 Arsenal Chelsea 5-3
2 Manchester Utd Arsenal 1-0
3 Liverpool Newcastle 2-0
4 Arsenal Everton 1-0
From this data, if I search for match_ids for matches played by Arsenal, I should get the below results,
1,2,4.
Now, in the basic designs which I know of, I would normally search for matched in team name for the team name supplied and return the result. But here the team name can be in two different columns and both can be relevant. So, is it something I need to decide on the design level or something that can be done with some sort of query.
(Note: Storing teams as home/away is not an option for my requirement).
You can just query both columns, it's not a problem:
select match_id
from matches
where team1 = 'Arsenal' or team2 = 'Arsenal';
(You could also normalize this schema by placing teams in their separate table and leaving only their ids in the matches table, but that doesn't change much, you still have to query both columns. Read about database normalization, any SQL book covers this).
If there are always two teams per match, then I think you did a good job here, and when querying for a particular team, you'll want to search for one column OR the other (SELECT match_id FROM matches WHERE team1 = "?" OR team2 = "?").
One note though: I would definitely split up the score into two columns:
match_id team1 team2 score1 score2
________ ______________ _________ ______ ______
1 Arsenal Chelsea 5 3
2 Manchester Utd Arsenal 1 0
3 Liverpool Newcastle 2 0
4 Arsenal Everton 1 0
This way you'll be able to query on scores later on, if you need it. (e.g. Big wins = SELECT match_id FROM matches WHERE ABS(score1 - score2) > 3;)
The other option you have should be more scalable if there exists a possibility of having more than two teams per match. If this is the case, then you'd likely want to remove the uniqueness constraint on match_id and cut out the team/score columns from 2 to 1:
match_id team score
________ ________ ____
1 Arsenal 5
1 Chelsea 3
2 Manchester Utd 1
2 Arsenal 0
3 Liverpool 2
3 Newcastle 0
4 Arsenal 1
4 Everton 1
And of course, you're definitely going to want to take Sergio's advice in putting all this stuff into separate tables. "Teams" are likely going to have different attributes (hometown, coach name, etc.), and you're not going to want to duplicate that data.
This will give you the results you want but there may be a better design too.
Select *
from table
where (team1 = 'ARSENAL' or Team2 = 'ARSENAL')
You may want to Separate out scores such as Team1Score Team2Score otherwise you can't easily do math with them.
for star I would not store the time name, I think its better if you store the times in other table and linq then thru an id.
And then you could create a table with columns id, match id and team id, and just search for the team id in that table!
you can used this query and its no problem for your program:
select YOUR_ID_FIELDS
from YOUR_TABLE_NAME
where YOUR_FIELD_NAME(team1) = 'Arsenal' or YOUR_FIELD_NAME(team2) = 'Arsenal';
and for exmale (Chelsea)
select YOUR_ID_FIELDS
from YOUR_TABLE_NAME
where YOUR_FIELD_NAME(team1) = 'Chelsea' or YOUR_FIELD_NAME(team2) = 'Chelsea';