Database Schema and Sql for a 5 star Rating - mysql

Requirements:
1. All "Users" have 5 fixed set of same "Services" which they are supposed to rate.
2. Given the userId, display all the Services and their corresponding "Ratings".
3. Rating would be from a scale of 1 - 5 only
4. Ratings can be updated anytime by the user for any of his Service.
I am no SQL/DB expert and I had this question up in stacks for which I got answer from Raj here ER Model of User Ratings
This is the ER I finalized (open for correction).
My Fetch Query: Get all the services and their corresponding for a userId (say userId = 1)
SELECT service.service_id, service.name, usr.ratings
FROM services service,
ratings ratings,
userservices_ratings usr,
user user,
user_services us
where
us.userid = user.uid and
us.serviceid = service.serviceid and
usr.usid = us.id and
usr.rid = ratings.rid and
user.id = 1
The above query will return all the services and ratings, only if User has rated the service. For services which are unrated don't make it to result set. So I assume I should pre-populate unrated services with a default value say 0?
All users will have fixed set of 5 services all the time, do I write a trigger to create his entry into User_Services table whenever a User is created?
How would the create/update query look if for example a Userid = 1, rates = 3 for serviceId = 1?
Any flaw in the schema?

You can standard format of Rating Schema here https://schema.org/Rating
You can pick required columns from this

Related

Showing null rows on a quiz application when user has no quiz results

Summary of problem: I have a CakePHP/MySQL web application. Users do quizzes to be awarded badges. Each quiz has a level (1 up to 5) to represent difficulty (1 = Easy, 5 = difficult).
I have 3 tables:
quizzes : A series of quizzes, each of which have a difficulty level 1 - 5 (quizzes.test_level) field and a unique ID (quizzes.id).
badge_structure : A list of quizzes which are required to gain a particular badge. Foreign key to 'quizzes' is badge_structure.quiz_id. This table contains multiple quizzes at each test_level.
results : A list of users results for a particular quiz. Foreign key is results.quiz_id. There is also a results.user_id to link to a 'users' table. Results are only stored in this table if the user has passed a quiz: If there is no results.quiz_id in this table for a given user, that user has not passed a particular quiz.
The problem I'm facing is I cannot work out which level the user has passed.
My application needs to show a star rating (1 - 5) based on quiz results for a given user. They must have completed all quizzes at a particular level (quizzes.test_level) to be awarded the star for a given badge, i.e.
quizzes.test_level = 1 (1 star)
quizzes.test_level = 2 (2 stars)
For the code below assume badge_structure.id = 3 (Badge number 3) and user.id = 257
SELECT MAX(q.test_level) AS badge_level
FROM badges_structure bs
JOIN quizzes q ON bs.quiz_id = q.id
JOIN results r ON bs.quiz_id = r.quiz_id
WHERE bs.badge_id = 3 AND r.user_id = 257
ORDER BY q.test_level ASC
This will give me the maximum test_level of a quiz a user has done, for a given badge. But I don't know whether they have passed that level, I only know that they have done quizzes that are within that level.
If I run something like this:
SELECT bs.badge_id, bs.quiz_id, q.test_level
FROM badges_structure bs
LEFT JOIN quizzes q ON bs.quiz_id = q.id
LEFT JOIN results r ON bs.quiz_id = r.quiz_id
WHERE bs.badge_id = 3 AND r.user_id = 257
ORDER BY q.test_level ASC
I can see the quizzes and levels they have done, but it doesn't tell me the whole badge_structure for that badge, because it's not including rows where they haven't yet got results.
How is it possible to see the badge structure and have a column which is 'null' if the user has no quiz results for a particular quiz ID?

Can somebody explain what is wrong with this INNER JOIN?

Simplified, I have three tables in a MySQL database:
sessions
- id
- title
- training_programme_id
session_attendees
- id
- sessions_id
- users_id
users
- id
- name
I am trying to count the number of sessions that a user is attending on a given training programme. When a user is set to attend a session, their ID is added to session_attendees.users_id and the session ID is added to session_attendees.sessions_id. Here is my SQL to count (as result) the number of sessions attended by a user with ID 10 when the training programme ID is 1:
SELECT count(*) AS result FROM session_attendees
INNER JOIN sessions
ON (session_attendees.sessions_id = sessions.id)
WHERE (session_attendees.users_id = 10 AND sessions.training_programme_id = 1);
Now I know from directly inspecting the database that session_attendees contains 7 sessions where users_id = 10 and all of those sessions have a training_programme_id = 1.
Am I misunderstanding an INNER JOIN?
EDIT:
Here's a couple of images to illustrate my tables:
As you can see I've sorted by user ID so you can see the 7 entries for ID = 10.

Calculate a variable using 2 Mysql tables and make a select based on that variable

I own an online game in which you become the coach of a rugby team and I recently started to optimize my database. The website uses CodeIgniter framework.
I have the following tables (the tables have more fields but I posted only those which are important now):
LEAGUES: id
STANDINGS: league_id, team_id, points
TEAMS: id, active
Previously, I was having in the LEAGUES table a field named teams. This was representing the number of active teams in that league (of which users logged in recently).
So, I was doing the following select to get a random league that has between 0 and 4 active teams (leagues with less teams first).
SELECT id FROM LEAGUES WHERE teams>0 AND teams<4 ORDER BY teams ASC, RAND( ) LIMIT 1
Is there any way I can do the same command now without having to add the teams field?
Is it efficient? Or It's better to keep the teams field in the database?
LATER EDIT
This is what I did until now:
function test()
{
$this->db->select('league_id, team_id');
$this->db->join('teams', 'teams.id = standings.team_id');
$this->db->where('active', 0);
$query = $this->db->get('standings');
return $query->result_array();
}
The function returns all inactive teams alongside with their league_id.
Now how do I count the number of inactive teams in each league and how to I sort them after this number?
Try this:
select league_id
from standings s
join teams t on t.id = s.team_id and t.active
group by 1
having count(*) < 5

MYSQL - How to check if a user is following another user, potentially through a subselect?

I'm fetching a list of activities (activities) and using a left join to grab the user data (users) who created the activity. Within my application users have the ability to follow one another.
This is my current query, which grabs all activities not posted by yourself ($user_id)
SELECT
activities.id, activities.user_id, users.id, users.name
FROM
activities
LEFT JOIN
users on activities.user_id = users.id
WHERE
users.id != $user_id
Aside from the activities + users tables, I have a another table in my application called followers:
followers
id | user_id_1 | user_id_2 | followed_back
1 1 3 1
2 2 3 0
3 3 1 1
I need to check whether you ($user_id) have followed a particular user joined to each activity and perhaps call this new field "user_followed" which represents a true/false/null value?
For example, I'm user_id = 1. Based on the above table, this means I have followed user_id 3. When an activity is fetched and user_id 3 is joined / responsible, the new field "user_followed" would be true.
Therefore, I think I'd need to incorporate another SELECT query, checking if the user is being followed:
(SELECT
*
FROM
followers
WHERE
user_id_1 = $user_id AND user_id_2 = users.id
)
I'm just largely unsure of how to incorporate this into my initial query and create a new field representing yes or no. Any help would be much appreciated!

Select certain field based on another field in table

I have three tables that I use which has proved this problem to be way out of my league.
The first is the hierachy table which looks like this
USER_ID, USER_LEVEL, Store_Manager_ID, Team_Manager_ID
------------------------------------------------------
1, 0, -, -
2, 1, 1, -
3, 2, 1, 2
4, 2, 1, 2
5, 2, 1, 2
This just shows the hierachy of the user. So user 1 has a level of 0 which means he is th store manager and so he has no store manager on top of him so his store manager id is nothing and team manager is obviously nothing.
The second user is the team manager and so level = 1 and store manager is 1(the first guy)
The third, forth and fifth are workers under 1 and 2 respectively.
The second is a login table which looks like this
USER_ID, EMAIL
--------------------------
1, john.smith#gmail.com
2, ron.jones#gmail.com
3, tom.graham#gmail.com
4, bill.small#gmail.com
The email is the login, no password.
The third is an alias table which looks like this
USER_ID, ALIAS_ID
--------------------
2, 5
The alias tables shows how user 5 is an alias of user 2. So he is the same person and has the same login. However he can be in two places in the hierachy at once i.e. a team manager and a worker at the same time.
My question is.
If I know that user 2 will be logging in as his alias, i.e. a worker before login.
When user 2 logs in, how can I select the id of the leader of the users account based on the level.
For example if I logged in as ron.jones#gmail.com (user 2) under my alias account.
The alias id of user 2 is 5 and based on the hierachy user 5 is level 2 i.e. a worker and so I should return the id of his team manager not his store manager.
So I would then return 2, i.e. himself (a little bizarre in the this case but besides the point)
This will give the answer you are looking for (if I understand the question correctly):
SELECT team_manager_id
FROM hierarchy h
INNER JOIN aliases a ON h.user_id = a.alias_id
INNER JOIN login l ON a.user_id = l.user_id
WHERE email = 'ron.jones#gmail.com';
Select user_ID, User_level, Store_Manager_ID, Team_Manager_ID
FROM Hierachy H
INNER JOIN Alias A on A.Alias_ID = H.User_Id
Where A.User_ID = 2
Assumes: that 1 a user doesn't have more than 1 alias, if it does you'll get multiple records back for the same user.
Assumes you don't carea bout the record 2 in hierachy as all you're after is 5.
If I understand correctly, you want the managers of a user, either based on the user or the alias for the user.
The following query does two joins, one to the user table and one to the alias table:
SELECT team_manager_id
FROM h.user_id = a.alias_id INNER JOIN
login l
ON a.user_id = l.user_id join
hierarchy huser
on huser.user_id = a.alias_id join
hierarchy halias
on halias.user_id = l.user_id
WHERE l.email = 'ron.jones#gmail.com' and
huser.team_manager_id is not null and
halias.team_manager_id is not null
It also checks that the manager is not null, returning only managers on the alias. This returns all such managers. Do you need a particular one, say from the lowest level of the hierarchy?