database design / mysql - mysql

My client is wanting to add new functionality to their site, they deal with actors/models and want to be able to create a credit history for each of the clients (much like a CV or Resume).
They have some criteria that I must adhere too, and because of this I cannot get my head around it.
A credit can be one of two things, it can be a 4 column credit, or a single column credit. The credit however must have a category, and these categories can be one of the following, TV, Film, Advert, Radio or something of their own making.
The second criteria is that the categories are orderable, so for example if they are entering an actors credit, he may have television and film credits, they may from time to time, to film above television.
The third criteria is that the credits with each category are orderable, so film1 credit does not have to be at the top.
Here is what I have devised so far.
CANDIDATES | CREDITS
---------- -------
candidate_id^ credit_id*
credit_category
credit_heading
credit_title
credit_role
credit_director
credit_position
candidates_candidate_id^^
^ - Primary Key
^^ - Foreign Key
My confusion comes from using this table structure there is no way to alter what order the categories are in, as if I added a credit_category_position.
For example if the user has a credit in the category film, and I want to add another, when I insert the data through my form, how do I keep the credit_category_position consistent for all that clients film entries?
I hope this makes sense to someone.

I've just glanced through your question and I'm not sure I exactly understand it, but one thing just pops to my mind:
why don't you have a many-to-many relationship between candidates and credits?
CANDIDATES | CREDITS
---------- -------
candidate_id^ credit_id*
credit_category
credit_heading
credit_title
credit_role
credit_director
CANDIDATE_CREDIT_REL
--------
rel_id*
credit_id^^
candidate_id^^
credit_position

A credit can be one of two things, it can be a 4 column credit, or a
single column credit.
I'm going to skip this one, because I don't understand it and because there isn't anything in your description that helps me with it. Feel free to edit your question.
The second criteria is that the categories are orderable
You need an additional table for that, because each candidate can have multiple credits in, say, film.
create table credit_category_order (
candidate_id integer not null,
credit_category <whatever> not null,
category_order float not null, -- lets you reorder by splitting the difference,
-- but there are other ways.
primary key (candidate_id, credit_category),
foreign key (candidate_id, credit_category)
references credits (candidate_id, credit_category)
);
The third criteria is that the credits with each category are
orderable
Add a column to credits. When you query, join credit_category_order, and ORDER BY credit_category_order.category_order, credits.credit_order.

Credit_Category
----------
id, category_name, details
Actor_cc_order //For each actor, have an entry for every category
----------
id, id_actor, id_cc, ord_number
Actor_credit
------------
id, id_actor, id_cc, credit_details
view of credits
SELECT a.*, b.category_name, c.ord_number FROM
Actor_credit a
JOIN Credit_category b ON b.id = a.id_cc
JOIN Actor_cc_order c ON c.id_actor = a.id_actor AND c.id_cc = b.id
SORT BY a.id_actor, c.order_number

Related

joining two tables in my sql desn't return a result set

Hi I have run in to a problem when retrieving a particular data set using 3 tables in a MySql database.Tables are as follows
Student
SID | Name | Age | Telephone
Term
TID | Start | End
Payment
PID | TID | SID | Value
SID is primary key of Student table. TID is primary key of Term table. PID is primary key of Payment table. TID and SID in Payment table are foreign key references.
Student table contains data of students. Term table contain data of term start and end dates. Payment table contain data about student payment. Records in Payment table may either contain TID or not. When it is a registration payment there will be no TID. Otherwise it is a term fee and there will be TID. What I want is a list of students that hasn't paid this terms fees until today. Asuume this TID is in a variable. How can I obtain the list of students ? IT SEEMS SUPER EASY. BUT I COULDNT FIND AN ANSWER THIS WHOLE DAY 😣
You want a list of just those students who do not have a TID-populated record whose start and end dates are either side of today, in Payment
SELECT * FROM
student
LEFT OUTER JOIN
(select * from payment where TID is not null and NOW() BETWEEN start and end) this_term_payments
on student.id = this_term_payments.sid
WHERE
this_term_payments.ID is null
There are many ways to skin this cat. Here is one. We filter the payments table down to just a list of this term's payments (that's the inner query). And left join that to students. Left join means we get all students, matched with this_term_payments if the this_term_payments row exists, or NULL in every this_term_payments column if the term payment doesn't exist. The where clause then filters the whole results set down to "just those who don't have a term payment" by looking for those nulls that the left join creates
FWIW, your question attracted close votes because it didn't include example data/demonstrate the level of your effort we like to see on SQL questions. If you'd included sample data for all your tables and an example result set you wanted to see out, it means we can write an exact query that meets your requirements.
This is a bit of a double edged sword for me; we can deliver exactly what you ask for even if you later realise it's not what you want (asking in English is far more vague than giving an example result set) but at the same time we basically become some free outsourced homework contractor or similar, doing your work for you and removing learning opportunities along the way. Hopefully you'll take this query (it's likely it doesn't output everything you want, or outputs stuff you don't want) and craft what you want out of it now that the technique has been explained.. :)
For an SQL question that was relatively well received (by the time i'd finished editing it following up on the comments), and attracted some great answers take a look here:
Fill in gaps in data, using a value proportional to the gap distance to data from the surrounding rows?
That's more how you need to be asking SQL questions - say what you want, give example data, give scripts to help people create your same data so they can have a play with their idea without the boring bits of creating the data first. I picked on that one because I didn't even have any SQL attempts to show at the time; it was just a thought exercise. Having nothing working isn't necessarily a barrier to asking a good question
Try this:
select s.name, p.value from Student s, Term t, Payment p where t.TID = p.TID and s.SID=p.SID and p.TID is null;

Multivalued attributes in MySQL

I am working on a database in MySQL to show multivalued attributes. I am trying to find a way to create a parent and child table. The idea that I am working with is having an employee table and a hobby table. The hobbies in the hobby table would be considered the multivalued attributes since employees can have more than one hobby. My question would be, when creating these tables, should I use 3NF and add a 3 table to show the relation between the two or is there a way to implement this idea with simply two tables. I’m not very familiar with multivalued attributes so I need help creating the tables as far as what kind of keys each would use, as well as the end form. I believe I would need to make it in 3NF form and have the hobbies as the multivalued attribute, but have the hobby id from the hobby table as a primary key and the employee id as another primary key and then making the relational table contain both the employee id and hobby id as foreign keys referencing the other two tables. Any help or suggestions to show multivalued attributes would be greatly appreciated!
You have a table for employees already. It probably has a primary key we'll call employee_id.
You need a table for hobbies. It will need a primary key we'll call hobby_id.
Then, you need a way to relate employees and hobbies many-to-many. That's implemented with a third table, let's call it employees_hobbies. Using a name like that is a good idea, because the next guy to work on your code will recognize its purpose right away.
employees_hobbies should have two columns, employee_id and hobby_id. Those two columns together should be the composite primary key. Then, to confer a hobby on an employee, you add a row to employees_hobbies containing the two id values. If an employee drops a hobby, you delete the row.
If you want a list of employees showing their hobbies, you do this
SELECT e.name, GROUP_CONCAT(h.hobbyname) hobbies
FROM employees e
LEFT JOIN employees_hobbies eh ON e.employee_id = eh.employee_id
LEFT JOIN hobbies h ON eh.hobby_id = h.hobby_id
GROUP BY e.employee_id, e.name
Use LEFT JOIN operations here to keep employees without any hobbies (all work and no play) in your list.
If you want to find the most common five hobbies and the employees doing them, try this
SELECT COUNT(*) hobbycount, h.hobbyname,
GROUP_CONCAT(e.name ORDER BY e.name) people
FROM hobbies h
LEFT JOIN employees_hobbies eh ON h.hobby_id = eh.hobby_id
LEFT JOIN employees e ON eh.employee_id = e.employee_id
GROUP BY h.hobbyname
ORDER BY 1 DESC
LIMIT 5
This way of handling many-to-many relationships gives you all kinds of ways of slicing and dicing your data.
MySQL is made for this sort of thing and handles it very efficiently at small scale and large, opinions to the contrary notwithstanding.
(Avoid putting a surrogate primary id key into your employees_hobbies table. It adds no value.)
mva is not very good for mysql .
and best way to store it depend from price you can pay and accessibility need . if you need index , because database is big , and highly loaded , then possible you will need 2 tables .
employee( id , name )
employee_hobbies ( id , employeeid , hobbyid )
but in simplest case , or if you need good accessibility, you can just add text field to employee table , store there comma separated hobbyid , and then select by FIND_IN_SET() function .
e.q. single table
employee( id , name , MVA VARCHAR(512) )
you need be sure that all ids comma separated will fit into fields , side .
SELECT * from employee where FIND_IN_SET(some_hobbyid , MVA)
advantage of this method is less queries ,
disadvantage - may slower then 1st .
also there is advantages for high load system , when import into sphinx ... but this is another story ...

Transition (many to many join) tables in MySQL; allowing for duplicate entries to link 1 column to multiple other columns in different table

Ok, so I am going to try and be specific as possible but my MySQL skills are pretty weak. So here is the situation:
I have 2 tables: Donor and Students. A donor can be linked to as many students as they want and each student can be linked to as many donors as donors want to "claim" them. So if I have Sally, a student, she can have Jim, a donor, and Jeff, a donor, be linked to her. So, I have all my students in one table and all my donors in another table. I need to put them together show the students name, id and the id of all the donors that the student is linked to.
Currently my tables are: Donor with DonorID, FirstName, LastName, DonorType, StreetAddress, etc. Then Students with: StudentID, FirstName, LastName and DonorID. However, that only allows me to link a student with one donor. So, I was thinking I need to make a transition table that would allow me to show the StudentID, FirstName(of student), LastName(of student), and the DonorID that "claims" that student and allow for me to duplicate StudentID and put a different DonorID in the 2nd, 3rd, 4th, so on and so on entries of the same student.
So, I guess my question is how do transition tables work in MySQL; I believe I am going to need to work with the JOIN function and join the two tables together but after reading about that on tizag.com I am even more confused. I have worked with Access where when you create a transition table you can pull the PK from each table and create a composite key using the two keys from the other tables but I am not quite sure how to do that in MySQL; does it work essentially the same and I should be pulling the PK from each table and linking them together in the 3rd, transition, table?
Marvin's right.
You need three tables to pull this off.
Donor
DonorID
FirstName
LastName
DonorType
StreetAddress
etc.
Student
StudentID
FirstName
LastName
etc.
Then you need Student_Donor. This is often called a join table, and implements the many-to-many relationship.
StudentID (PK) (FK to Student)
DonorID (PK) (FK to Donor)
DonorOrdinal
If StudentID = 5 has four donors with ID = 6,7,11,15, then you'l have these rows
StudentId DonorId DonorOrdinal
5 6 1
5 7 2
5 11 3
5 15 4
The DonorOrdinal column allows you to specify a student's primary donor and secondary donors. I can't tell from your question how important that is, but it's helpful to be able to order these things. Remember this: formally speaking, a SQL SELECT query returns rows in an unpredictable order unless you also specify ORDER BY.
If you want to display your students and their donors, you'll need this query:
SELECT s.StudentID, s.FirstName, s.LastName,
sd.DonorOrdinal,
d.DonorType, d.DonorID, d.FirstName, d.LastName
FROM student s
LEFT JOIN student_donor sd ON s.StudentID = sd.StudentID
LEFT JOIN donor d ON sd.DonorID = d.DonorID
ORDER BY s.StudentID, sd.DonorOrdinal, d.DonorID
This will show you all students (whether having donors or not per LEFT JOIN) in order of ID, then their donors in order of DonorOrdinal.
Yes, pretty much. What you are talking about is a Many to Many relationship. Your donor table should not include a reference to the student table (and vice versa). You'll need a new table (what you are calling a transition table) that contains the DonorId and StudentId. This can comprise your primary key or you can use another column for the primary key that is an auto_increment.

Mysql setup for multiple users with large number of individual options

i'm building a study tool and i'm not sure of the best way to go about structuring my database.
Basically, i have a simple but big table with around 50000 bits of information in it.
info (50'000 rows)
id
info_text
user
id
name
email
password
etc
What i want is for the students to be able to marked each item as studied or to be studied(basically on and off), so that they can tick off each item when they have revised it.
I want to build tool to cope with thousands of users and was wondering what the most efficient/easiest option way of setting up the database and associated queries.
At the moment i would lean towards just having one huge table with two primary keys one with user id and then id of the info they had studied and then doing some sort of JOIN statement so i could only pull back the items that they had left to study.
user_info
user_id
info_id
Thanks in advance
Here is one way to model this situation:
The table in the middle has a composite primary key on USER_ID and ITEM_ID, so a combination of the two must be unique, even though individually they don't have to be.
A user (with given USER_ID) has studied a particular item (with given ITEM_ID) only if there is a corresponding row in the STUDIED table (with these same USER_ID and ITEM_ID values).
Conversely, the user has not studied the item, if and only if the corresponding row in STUDIED is missing. To pull all items a given user hasn't studied, you can do something like this:
SELECT * FROM ITEM
WHERE NOT EXISTS (
SELECT * FROM STUDIED
WHERE
USER_ID = <given_user_id>
AND ITEM.ITEM_ID = STUDIED.ITEM_ID
)
Or, alternatively:
SELECT ITEM.*
FROM ITEM LEFT JOIN STUDIED ON ITEM.ITEM_ID = STUDIED.ITEM_ID
WHERE USER_ID = <given_user_id> AND STUDIED.ITEM_ID IS NULL
The good thing about this design is that you don't need to care about STUDIED table in advance. When adding a new user or item, just leave the STUDIED alone - you'll gradually fill it later as users progress with their studies.
I would do something like this:
1) A users table with a uid primary key
2) A enrolled table (this table shows all courses that have enrolled students) with a primary key of (uid, cid)
3) A items (info) table holding all items to study, with a primary key of itemid
Then in the enrolled table just have one attribute (a binary flag) 1 means it has been studyed and 0 means they still need to study it.

What do I need in a database for "Customers Who Bought This Item Also Bought"?

Amazon has "Customers Who Bought This Item Also Bought".
I am wondering and want to add this to my shopping cart which I made.
What fields do I need in a database? Any website, blog or resources for this?
Can you suggest the mechanism how to I should code it please?
Here are some similar questions:
How do recommendation systems work?
Design of the recommendation engine database?
How to create my own recommendation engine?
Techniques for building recommendation engines?
Where can I learn about recommendation systems?
You probably don't need any new fields in your database - just keep a history of your orders. Then when you want to find your list of what other people bought:
Select all users who have an order containing Item X
For each of those users, total up everything else they have bought
Get the top 3/5/whatever and there's your list.
It's not too tricky. Assume you have the following tables:
Customers, primary key CustomerID
Products, primary key ProductID
Orders, primary key OrderID, foreign key CustomerID
OrderItems, primary key OrderItemID, foreign keys OrderID, ProductID
To find the products you seek, you need to find the set of customers who have bought that particular product ID:
SELECT CustomerID
FROM (Customers INNER JOIN (Orders INNER JOIN OrderItems))
WHERE OrderItem.ProductID = <your product id here>
Then, you need to get the other products those customers have bought:
SELECT ProductID
FROM (Customers INNER JOIN (Orders INNER JOIN OrderItems))
WHERE (Customer = <given customer ID>) AND (ProductID <> <your product id>)
Then select the top few products and you're off to the races.
Note: I'm a numerical guy. The DB gurus will be able to do this in 1 query! :)
You need history of orders so that you can check for other items that were bought together with the item user is currently viewing.
You need "Programming Collective Intelligence". They have some nice chapters about recommendations and such. You'll want to read about Pearson differences and other measures.
Have a look at Algorithms of the intelligent web, chapter 3 "Creating suggestions and recommendations". For your question: optionally, you might need a table with user ratings for different items. Based on these ratings, you will be able to measure similarity between two clients and then perform an estimation based on these values on the items one of client is about to achieve. These estimations are used to rank the items.
Also, have a look at the Apriori algorithm chapter 4 or a general description of it here; this works for items bought together and extract some associations rules. Based on these rules, you will detect which of the items you sell might be added to the client's basket. For your question: no additional field should be added to your database; you have to maintain only a table to group items purchased together (market baskets contents).
select `A`.`ORDER_NO`, `A`.`SKU`, `B`.`SKU` `REL_SKU`
from `order_detail` `A`
inner join
(select DISTINCT `ORDER_NO`, `SKU`
from `order_detail`) `B`
on `B`.`ORDER_NO` = `A`.`ORDER_NO`
WHERE `B`.`SKU` = 'XXXXXXXX'
AND `A`.`SKU` <> 'XXXXXXXX'
This works for me. of course add in any filters in the where clause as appropriate such as order status etc...