Database table column that has multiple table foreign key - mysql

Lets consider three tables :
1.Companies
id
company_name
...
2. Employees
id
employee_name
...
3. Payment
id
pay_by
pay_to
...
Now the problem is here pay_to can be id of a Company or an Employee (fk). So I have added a Boolean column "is_company" in the Payment Table. So my solution is if is_company is True then its Company otherwise its Employee.
But I am not satisfied with this solution. I mean I don't want to have a column which has multi table foreign key. I think there has a better solution but I could not find that. Please help to find a better solution. Thanks in advance.

You could, depending on what you using to interact with the database, prefix the pay_to with a letter, e for employee or c for company however then you can't specify that the field is an int etc which may cause issues.
One alternative is to use different ranges (this would obviously limit the number of each you could have) but you could say 0-9999999 is employees and 10000000+ is company ID's.
Another alternative would be to have an interim table (called payees for example) where pay_to references a row in that table which gives you a payee type and then the payee's ID in their respective table.
--EDIT--
You could create a table called payees with columns such as payee_id, payee_type, id. payee_id would be an auto increment column that you would then reference in the payment.pay_to field. payee_type would be company/employee and then id would either be company.id or employee.id depending on the type. It would mean using 2 queries rather than using a join but that is true with any of the possibilites unless you could combine companies and employees in to one table - this would depend on the other columns beyond what you have detailed in your original question.
None of them are necessarily elegant (and there may and probably are other) solutions, but they would be the 3 I would look at using in your situation!

to build on what Ed Wade said, you could prefix all companies with a 1 and all employees with a 2. This would help with keeping the field as an integer while not limiting the number you could store

Related

How to implement SQL join on multiple keys for two tables using where clause?

I am interested to find the student headcount of 1st week of fall 2018 for the Business faculty by sex using the following two tables. Here ID is the primary key or part of the primary key for each of the data tables. In plan table, the program is the student's college(for our case, "Business"), Sex has values M, and F, TERM has the values, "Fall", "Spring", and " Summer", Sessions has the values, " 1st week", and " 2nd week". I was wondering if you could check my code. I am kinda new in SQL! I sincerely appreciate your time.
My SQL code:
SELECT count(Student.ID) as COUNT, Student.Sex as Sex
FROM Student JOIN Plan
on Student.ID=Plan.ID
WHERE Student.Term="Fall"
AND Student.Sessions="1st Week"
AND Plan.Program="Business"
GROUP BY Student.Sex;
The answer to this depends on whether or not the ID column in the plan table is the student’s id number , which i believe it is not. The plan table should have an entry for each student session combination, in order to account for the same student having different sessions. See: one to many relationship. From there, you should be able to execute this query after you group by all of the fields mentioned in the select clause.
Anyway, I've created the fiddle for you reference here :
https://www.db-fiddle.com/f/7G2DwLB6SNqbAtKeD96nWG/1
And I can conclude that based on you query condition given, it is correct. But like #Benny mention, the field ID is usually referring to the tables data ID. For example ID in Student is the student id while in Plan its highly possible that its ID for each plan. But you said it's identical AND there's no student_id column in the Plan table, so it should be ok.

SQL Table for Groups ? Which solution would be better?

I'm trying to setup groups in my network using MySQL. Users could join in groups or create groups. Of the two options below, I'm trying to identify which solution is better.
First Solution:
I create a Table called "Groups" with columns:
- GroupID
- GroupName
- Createtime
- GroupMembers...
In this solution I would save the users in the column GroupMembers like this "user1;/user2;/" and so on. This is my first solution; I don't know if this would be faster than the second solution. I just want to lookup GroupMembers, etc.
Second Solution:
I would create a table like in the first solution, but without the column GroupMembers, and I would create a second table for the GroupMembers.
This table will have following columns:
-GroupID //The ID of the group in the other table.
-UserID
When joins a group, it will be stored in the above table.
The first solution is Bad because it breaks normalization.
The second solution is Good.
The typical approach would be to have a Users table, a Groups table and a UserGroups (or GroupUsers) table

Creating a relationship between three tables

There are many ways I can think of to hack this together, but I want to know what the best practice is here:
I have three tables. Products, Pricelists and Prices.
One product can belong to many pricelists.
One pricelist can belong to many products.
This is a many to many relationship and as far as I know requires a Junction table (pricelist_products). Which works well.
Now, one product within a pricelist can have multiple prices. A product is only ever given a price once its within a pricelist.
What I've thought about here is using the ID from the junction table 'pricelist_products' as a foreign key within the prices table, but this feels really.... hacky?
Fishy example:
Product 1 - Fishing Rod.
Pricelist A - Fishermen.
Pricelist B - Fishingshop.
Pricelist A, Product 1, price 1:
(Monthly repayments option 1 (no deposit))
Pricelist A, Product 1, price 2:
(Monthly repayments option 2 (with deposit))
Pricelist A, Product 1, price 3:
(Quaterly repayments)
Pricelist B, Product 1, price 1:
(Quaterly repayments)
What I've thought about here is using the ID from the junction table 'pricelist_products' as a foreign key within the prices table, but this feels really.... hacky?
Maybe the issue here is just one of perspective. The purpose of the junction table is to uniquely define each combination within your many-to-many relationship (initially: pricelist to product). This can be achieved in the junction table with the fields product_id and pricelist_id alone, and without the surrogate key id.
Of course, if you defined your junction table with PRIMARY KEY (product_id, pricelist_id), this table would lack the ability to uniquely define combinations when price is considered. So you add a third id to the junction table. It appears you were looking at this field as a necessary surrogate key when defining a relationship between only two tables. However, since the real utility of this field relates to the third table, you might name it price_id instead, name your junction table pricelist_product_price, and define the primary key on all three fields (for example). This more clearly demonstrates the purpose of each field, and so may not feel "hacky" in practice.
I don't know if this is a best practice for database design, but keep in mind that there is no reason you must fully normalize every database. You want good performance with reasonable amount of flexibility and scalability (this can mean one thing for a casual blog, and quite another thing for a small business), and that can often be achieved with some degree of non-normalized design.
Edited to add: Okay, there is one other change I forgot to mention that would fall under "good" design or best practices. In your picture, you have two ID fields in the price table where one would be sufficient. As #Gilbert Le Blanc pointed out, you should try to avoid ambiguous field names like having multiple id fields, even if they are in different tables. This will help you see the utility of your fields, identify natural keys, and eliminate redundancies.
If you would not use anywhere else the relation between products and price lists but for prices then an alternative design is like this:
-Table products with fields: id, others
-Table pricelists with fields: id, others
-Table prices with fields: id (autoincrement), product_id, pricelist_id, price
and you would define index (not unique) on the pair of fields product_id, pricelist_id

The optimal way to store multiple-selection survey answers in a database

I'm currently working on a survey creation/administration web application with PHP/MySQL. I have gone through several revisions of the database tables, and I once again find that I may need to rethink the storage of a certain type of answer.
Right now, I have a table that looks like this:
survey_answers
id PK
eid
sesid
intvalue Nullable
charvalue Nullable
id = unique value assigned to each row
eid = Survey question that this answer is in reply to
sesid = The survey 'session' (information about the time and date of a survey take) id
intvalue = The value of the answer if it is a numerical value
charvalue = the value of the answer if it is a textual representation
This allowed me to continue using MySQL's mathematical functions to speed up processing.
I have however found a new challenge: storing questions that have multiple responses.
An example would be:
Which of the following do you enjoy eating? (choose all the apply)
Girl Scout Cookies
Bacon
Corn
Whale Fat
Now, when I want to store the result, I'm not sure of the best way to handle it.
Currently, I have a table just for multiple choice options that looks like this:
survey_element_options
id PK
eid
value
id = unique value associated with each row
eid = question/element that this option is associated with
value = textual value of that option
With this setup, I then store my returned multiple selection answers in 'survey_answers' as strings of comma separated id's of the element_options rows that were selected in the survey. (ie something like "4,6,7,9") I'm wondering if that is indeed the best solution, or if it would be more practical to create a new table that would hold each answer chosen, and then reference back to a given answer row which in turn references back to the element and ultimately the survey.
EDIT
for anyone interested, here is the approach I ended up taking (In PhpMyAdmin Relations View):
And a rudimentary query to gather the counts for a multiple select question would look like this:
SELECT e.question AS question, eo.value AS value, COUNT(eo.value) AS count
FROM survey_elements e, survey_element_options eo, survey_answer_options ao
WHERE e.id = 19
AND eo.eid = e.id
AND ao.oid = eo.id
GROUP BY eo.value
This really depends on a lot of things.
Generally, storing lists of comma separated values in a database is bad, especially if you plan to do anything remotely intelligent with that data. Especially if you want to do any kind of advanced reporting on the answers.
The best relational way to store this is to also define the answers in a second table and then link them to the users response to a question in a third table (with multiple entries per user-question, or possibly user-survey-question if the user could take multiple surveys with the same question on it.
This can get slightly complex as a a possible scenario as a simple example:
Example tables:
Users (Username, UserID)
Questions (qID, QuestionsText)
Answers (AnswerText [in this case example could be reusable, but this does cause an extra layer of complexity as well], aID)
Question_Answers ([Available answers for this question, multiple entries per question] qaID, qID, aID),
UserQuestionAnswers (qaID, uID)
Note: Meant as an example, not a recommendation
Convert primary key to not unique index and add answers for the same question under the same id.
For example.
id | eid | sesid | intval | charval
3 45 30 2
3 45 30 4
You can still add another column for regular unique PK if needed.
Keep things simple. No need for relation here.
It's a horses for courses thing really.
You can store as a comma separated string (But then what happens when you have a literal comma in one of your answers).
You can store as a one-to-many table, such as:
survey_element_answers
id PK
survey_answers_id FK
intvalue Nullable
charvalue Nullable
And then loop over that table. If you picked one answer, it would create one row in this table. If you pick two answers, it will create two rows in this table, etc. Then you would remove the intvalue and charvalue from the survey_answers table.
Another choice, since you're already storing the element options in their own table, is to create a many-to-many table, such as:
survey_element_answers
id PK
survey_answers_id FK
survey_element_options_id FK
Again, one row per option selected.
Another option yet again is to store a bitmask value. This will remove the need for a many-to-many table.
survey_element_options
id PK
eid FK
value Text
optionnumber unique for each eid
optionbitmask 2 ^ optionnumber
optionnumber should be unique for each eid, and increment starting with one. There will impose a limit of 63 options if you are using bigint, or 31 options if you are using int.
And then in your survey_answers
id PK
eid
sesid
answerbitmask bigint
Answerbitmask is calculated by adding all of the optionbitmask's together, for each option the user selected. For example, if 7 were stored in Answerbitmask, then that means that the user selected the first three options.
Joins can be done by:
WHERE survey_answers.answerbitmask & survey_element_options.optionbitmask > 0
So yeah, there's a few options to consider.
If you don't use the id as a foreign key in another query, or if you can query results using the sesid, try a many to one relationship.
Otherwise I'd store multiple choice answers as a serialized array, such as JSON or through php's serialize() function.

Did I overdesign my MySQL database (users/companies/products)?

I'm new to database design,
please give me advice about this.
1 When should I use a composite index?
im not sure what does index does, but
i do know we should put it when it
will be heavly loaded like for WHERE
verified = 1 and in search like
company.name = something. am i right ?
2 MySQL indexes - how many are enough?
is it just enough ?
3 Database Normalization
is it just right?
Thanks.
edit*
rules.
each users( company member or owners ) could be a member of a
company
each company have some member of users.
there are company admins ( ceo, admins) and there are company members
( inserts the products )
each company can have products.
for the number 3 i will add a bit at users_company
- 1 is for admin
- 0 is for members
Looks good, well normalised, to me at least.
I notice that each product can only belong to one company. If that's what you intended that's fine, otherwise you could have product have its own PID and have a product_company relation table, which would let more than one company sell a particular product. Depends who administers the products I guess.
I did notice that the user table is called 'users' (plural) and the others are singular ('company', 'product'). That's only a minor thing though.
The only comment I have is that you may want to consider just adding a mapping_id column to your users_company table and making CID and UID foreign keys, and add a UNIQUE constraint.
This way you can have a distinct Primary Key for records in that table which isn't dependent on the structure of your other tables or any of your business logic.