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
Related
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.
Note: This is not an inventory controlling system. I am just trying to map which medication given to which patient. I am not considering how many medication packets etc. Just a single medication event
I am having a sudden confusion with database relationships, even after working with them for years. Below is my situation.
I have a table called patient where it will hold the information of patients. I have another table called medication where it will hold the medicines prescribed for patients.
I want to find the relationship, so I asked the below questions from me.
Can one patient have many medicine prescribed? - Answer: YES
Can one prescribed medicine have many patients? - Answer: No (ex: you can't give a patient a paracetamol to drink, take it out and give it to someone else)
I need to create the foreign key of patient in medication table. I'm confused, because my answer for 1st question tell me it is one to many relationship while the answer for 2nd says me it is one to one relationship.
What is the exact relation when I am planning to add the foreign key of patient in medication table?
Below is my structure
It somewhat depends on the kind of structure of your tables.
Example 1
Patient:
PatientID Name
--------- ----
1 John
2 Matt
Patient_Medication:
PrescriptionID PatientID Name
-------------- --------- ------------
1 1 Antacid
2 1 Paracetamol
3 2 Asthma inhaler
You are in a one to many relationship. Patient John can have multiple medications in prescription table.
Example 2
Patient:
PatientID Name
--------- ----
1 John
2 Matt
3 Katie
Medication:
MedicationID Name
------------ ----
1 Antacid
2 Paracetamol
3 Asthma inhaler
Patient_Medication:
ID PatientID MedicationID
--- --------- ------------
1 1 (John) 1 (Antacid)
2 1 (John) 2 (Paracetamol)
3 2 (Matt) 3 (Asthma inhaler)
4 3 (Katie) 2 (Paracetamol)
5 3 (Katie) 3 (Asthma inhaler)
This situation is a many-to-many relationship where many patients can have many medications and vice versa. Usually Patient_Medication is called a junction table.
Your second question:
Can one prescribed medicine have many patients? - Answer: No (ex: you can't give a patient a paracetamol to drink, take it out and give it to someone else)
I guess here you have assumed that prescribing a medication and actually consuming that mediation (actual tablet) in real world is the same thing.
The medication table is just a name holder for the medication.
Your answer would have been correct if your table "Medication" would be storing actual instances of medication.
E.g.
Medication
Id Name
1 Paracetomol 25mg Instance 1
2 Paracetomol 25mg Instance 2
3 Paracetomol 25mg Instance 3
Now here, table is actually containing medication instances which can not be consumed by two patients. And here your answer "No" is, I guess, correct.
The other thing is, as you said you are not working on inventory system, and just trying to map medication, you are still attached to real world inventory item which cannot be consumed by two patients.
Here you are mixing inventory item in a system where inventory item is not required.
I think the relationship should actually be many-to-many. A given patient record could point to several different medications, and similarly a given medication record could point to several different patients.
One way to implement this would be to create a third table which maps patients to medications (or medications to patients, if you prefer to think of it that way). This table might look like this:
id | patient_id | medication_id | date
1 | 1 | 1 | 2016-12-19
2 | 1 | 2 | 2016-12-18
3 | 2 | 2 | 2016-12-18
The above data would imply that patient 1 took medications 1 and 2, and medication 2 was also being taken by patient 2. I also added a date, which might be a proxy for a given patient visit.
The medication_id could be a unique identifier for a given pack of medication delievered. In another table, each unique medication would be related to a parent table for that medication.
Update:
Your current schema does not look far off, except that the table you labelled medication is actually a bridge table between patients and their medication dosages. You would need a third table which stores the metadata for each medication. This metadata would be constant for all medication dosages, e.g. type of drug, cost, etc.
Could your confusion be the result of not having defined what the medication table actually represents. It seems to me that your are confusing type of medicine and actual packets.
So what kind of relationship are you trying to model? Are you doing a system that can do inventory of how much medicine you have, or are you doing a patient system that can tell you how many patients are getting a particular medication.
I think your answer to question two is wrong, many patients can be on the same medication. The number of packets you have in stock should be handled in a separate table where you could hold information on things like how many packets you have, what their location is and so on.
So you need at least three tables
patient - holds the patient
medication - holds the types of medication
patient_medication - holds the information on what types of medication the patient is on
you can then add things like another table to hold information on how much of a medication you have and where it's stored if that is relevant to the system.
It's not wrong to say that the association is one-to-many in one direction, and one-to-one in the other direction. When planning a database, I often advise people to write out the associations in both directions:
Each patient can have zero or more medications
Each medication belongs to one and only one patient
This helps to determine the cardinality of the relationship and clarify functional dependencies. When only one direction is specified, it can be difficult to distinguish one-to-many from many-to-many associations.
When talking about the relationship as a whole, we take an "overhead perspective" and ignore the perspective of individual entities, so we would call this example one-to-zero-or-more, or commonly just one-to-many.
Many-to-many relationships look like two one-to-many associations when you view it from the perspective of individual entities on either side.
I'm trying to come up with a database design for the following scenario.
Student can register to a Programme, at a given time student can have
only one registered programme.However, he/she must be able to change
the registered programme at any given time (including registering to a new programme). Ultimately, student can be
registered to multiple programme but he must have only 1 active
programme.
I think it should be a 1-M relationship but how to handle this "1 active programme at a given time" situation?
Your student table will have the ProgramID in relation to the Program table for example that he/she chooses and would be the current program. Now, every time he/she change his/her program that ProgramID will change however there will be a ProgramHistory to record the changes.
So possible table would be Student, Program, ProgramHistory.
Example:
Student
StudentID Lastname Firstname Gender ProgramID
------------------------------------------------------
101 Smith Jason M 1
102 Jones Kate F 2
Program
ProgramID ProgramName
------------------------------
1 Computer Science
2 Nursing
3 Electrical Engineering
ProgramHistory
ID ProgramID StudentID Semester Year
-----------------------------------------------------
1 3 101 Spring 2014
2 2 102 Fall 2014
3 1 101 Fall 2014
To allow for tracking of the history of program enrollment, you need to have a ProgramHistory table that is the intersection of a many-to-many relationship between Student and Program
There are a couple of ways to ensure that there is only one active program at one time for a given student.
One way would be to put an active_program_key column in your student table and make it a foreign key to the Program table. This is probably not the best alternative, since it requires denormalizing data and the resulting duplication might result in data inconsistencies unless you take significant steps to avoid them.
Another option using declarative constraints is to create a unique index on the ProgramHistory table that includes the student_key and the enrollment_date. This ensures that a student can only enroll in once per given date. The active program will be the record with the latest date for any given student.
This second option is simple and avoids duplicating any data. In fairness, the query to retrieve current student enrollments will be slightly more complicated. As always, design is about trade-offs.
Assuming that students can change programs at just about any time (i.e. not just between semesters) then you want to have a program_start_date in your ProgramHistory table.
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.
QUESTION: Is it okay to have "shortcut" identifiers in a table so that I don't have to do a long string of joins to get the information I need?
To understand what I'm talking about, I'm going to have to lay ouf an example here that looks pretty complicated but I've simplified the problem quite a bit here, and it should be easily understood (I hope).
The basic setup: A "company" can be an "affiliate", a "client" or both. Each "company" can have multiple "contacts", some of which can be "users" with log in privileges.
`Company` table
----------------------------------------------
ID Company_Name Address
-- ----------------------- -----------------
1 Acme, Inc. 101 Sierra Vista
2 Spacely Space Sprockets East Mars Colony
3 Cogswell Cogs West Mars Colony
4 Stark Industries Los Angeles, CA
We have four companies in our database.
`Affiliates` table
---------------------
ID Company_ID Price Sales
-- ---------- ----- -----
1 1 50 456
2 4 50 222
3 1 75 14
Each company can have multiple affiliate id's so that they can represent the products at different pricing levels to different markets.
Two of our companies are affiliates (Acme, Inc. and Stark Industries), and Acme has two affiliate ID's
`Clients` table
--------------------------------------
ID Company_ID Referring_affiliate_id
-- ---------- ----------------------
1 2 1
2 3 1
3 4 3
Each company can only be a client once.
Three of our companies are clients (Spacely Space Sprockets, Cogswell Cogs, and Stark Industries, who is also an affiliate)
In all three cases, they were referred to us by Acme, Inc., using one of their two affiliate ID's
`Contacts` table
-----------------------------------------
ID Name Email
-- -------------- ---------------------
1 Wylie Coyote wcoyote#acme.com
2 Cosmo Spacely boss#spacely.com
3 H. G. Cogswell ceo#cogs.com
4 Tony Stark tony#stark.com
5 Homer Simpson simpson#burnscorp.com
Each company has at least one contact, but in this table, there is no indication of which company each contact works for, and there's also an extra contact (#5). We'll get to that in a moment.
Each of these contacts may or may not have a login account on the system.
`Contacts_type` table
--------------------------------------
contact_id company_id contact_type
---------- ---------- --------------
1 1 Administrative
2 2 Administrative
3 3 Administrative
4 4 Administrative
5 1 Technical
4 2 Technical
Associates a contact with one or more companies.
Each contact is associated with a company, and in addition, contact 5 (Homer Simpson) is a technical contact for Acme, Inc, and contact 4 (Tony Stark) is a both an administrative contact for company 4 (Stark Industries) and a technical contact for company 3 (Cogswell Cogs)
`Users` table
-------------------------------------------------------------------------------------
ID contact_id company_id client_id affiliate_id user_id password access_level
-- ---------- ---------- --------- ------------ -------- -------- ------------
1 1 1 1 1 wylie A03BA951 2
2 2 2 2 NULL cosmo BF16DA77 3
3 3 3 3 NULL cogswell 39F56ACD 3
4 4 4 4 2 ironman DFA9301A 2
The users table is essentially a list of contacts that are allowed to login to the system.
Zero or one user per contact; one contact per user.
Contact 1 (Wylie Coyote) works for company 1 (Acme) and is a customer (1) and also an affiliate (1)
Contact 2 (Cosmo Spacely) works for company 2 (Spacely Space Sprockets) and is a customer (2) but not an affiliate
etc...
NOW finally onto the problem, if there is one...
Do I have a circular reference via the client_id and affiliate_id columns in the Users table? Is this a bad thing? I'm having a hard time wrapping my head around this.
When someone logs in, it checks their credentials against the users table and uses users.contact_id, users.client_id, and users.affiliate_id to do a quick look up rather than having to join together a string of tables to find out the same information. But this causes duplication of data.
Without client_id in the users table, I would have to find the following information out like this:
affiliate_id: join `users`.`contact_id` to `contacts_types`.`company_id` to `affiliates`.`company_id`
client_id: join `users`.`contact_id` to `contacts_types`.`company_id` to `clients`.`company_id`
company_id: join `users`.`contact_id` to `contacts_types`.`company_id` to `company`.`company_id`
user's name: join `users`.`contact_id` to `contacts_types`.`contact_id` to `contacts`.`contact_id` > `name`
In each case, I wouldn't necessarily know if the user even has an entry in the affiliate table or the clients table, because they likely have an entry in only one of those tables and not both.
Is it better to do these kinds of joins and thread through multiple tables to get the information I want, or is it better to have a "shortcut" field to get me the information I want?
I have a feeling that over all, this is overly complicated in some way, but I don't see how.
I'm using MySQL.
it's better to do the joins. you should only be denormalizing your data when you have timed evidence of a slow response.
having said that, there are various ways to reduce the amount of typing:
use "as" to give shorter names to your fields
create views. these are "virtual tables" that already have your standard joins built-in, so that you don't have to repeat that stuff every time.
use "with" in sql. this lets you define something like a view within a single query.
it's possible mysql doesn't support all the above - you'll need to check the docs [update: ok, recent mysql seems to support views, but not "with". so you can add views to do the work of affiliate_id, client_id etc and treat them just like tables in your queries, but keeping the underlying data nicely organised.]