Getting X results from SQL with multiple tables - mysql

(Sorry for my bad english, I'll try to be the clearest)
I want to select 5 conversations (over an undetermined number, there could be 5 or 300 conversations) of one user in a MySQL table, and for each of those, I want to select all the users who talk in it.
In a wonderfull world, I'd like to do it with one query.
My query looks like (tables are in french, plz don't hurt me) :
SELECT mc.mc_id, mc.mc_sujet, mc.mc_statut,
miu.mi_ustatut as uself_statut, miu.mi_datelecture as uself_datelecture,
mi.mi_uid, mi.mi_ustatut, mi.mi_datelecture,
u.u_pseudonyme
FROM msg_individus as miu
LEFT JOIN msg_conversations as mc ON mc.mc_id = miu.mi_mcid
LEFT JOIN msg_individus as mi ON mi.mi_mcid = mc.mc_id
LEFT JOIN u_individus as u ON u.u_id = mi.mi_uid
WHERE miu.mi_uid = :u_id
Where msg_individus is the table with participants of a conversation,
msg_conversations is the table of the conversation (id, subject, status),
u_individus is the table with users' informations.
To select only 5 of those conversations, I added something like
GROUP BY mc.mc_id,
LIMIT 0,5
But of course, only one user per conversation is given is this way.
I also tried to write GROUP BY mc.mc_id, mi.mi_uid but this, like no writting a GROUP BY condition, returns 5 iterations like :
(Conversation 1 has two users, conversation 2 has one, conversation 3 has four)
Iteration 1 : conversation 1, user 1
Iteration 2 : conversation 1, user 2
Iteration 3 : conversation 2, user 1
Iteration 4 : conversation 3, user 1
Iteration 5 : conversation 3, user 2
What I want is to get five CONVERSATIONS with all their datas (whatever the number of users in it, etc)
I guess I'll have to use two queries (after getting the 5 conversations, I'll get the users per conversations), but maybe you guys can light me with your knowledges.
Thx.

Use a subquery to get five conversations. I also suggest that you replace the outer joins with inner joins. I think the table keys should all have matches:
SELECT mc.mc_id, mc.mc_sujet, mc.mc_statut,
miu.mi_ustatut as uself_statut, miu.mi_datelecture as uself_datelecture,
mi.mi_uid, mi.mi_ustatut, mi.mi_datelecture,
u.u_pseudonyme
FROM (SELECT miu.*, mc.*
FROM msg_individus miu JOIN
msg_conversations mc
ON mc.mc_id = miu.mi_mcid
WHERE miu.mi_uid = :u_id
ORDER BY rand() -- not necessary, but why not?
LIMIT 5
) ic
msg_individus mi
ON mi.mi_mcid = ic.mc_id JOIN
u_individus u
ON u.u_id = ic.mi_uid;

Related

how to select specific rows in some condition

I tried to write a query that selects rows with steps that both user 1 and user 2 did, with combined number of times they did the step (i.e., if user 1 did step 1 3 times and user 2 did 1 time then the count should show 4 times.)
when I put condition as user_id=1, user_id=2 there is no error but it return nothing, when it should return some rows with values.
there is table step, and step taken
and table step has column id, title
table step_taken has column id, user_id(who performs steps), step_id
i want to find step that both of two user whose id 1,2 did
and also want to have the value as count added up how many times they performed that step.
for example if user id 1 did step named meditation 2 times,
and user id 2 did step named meditation 3 times,
the result i want to find should be like below ;
------------------------------
title | number_of_times
------------------------------
meditation| 5
------------------------------
here is my sql query
select title, count(step_taken.step_id)as number_of_times
from step join step_taken
on step.id = step_taken.step_id
where user_id = 1 and user_id=2
group by title;
it returns nothing, but it should return some rows of step both user1 and user 2 did.
when i wrote same thing only with user_id=1 or user_id=2, it shows selected information
how can I fix my code so it can show the information I want to get?
thanks in advance :)
user_id cannot be 1 and 2 at the same time. You need a second user table. Then join those on your criteria and count:
select title, count(u1.id) + count(u2.id) as number_of_times
from step u1 join step u2
on u1.id = u2.id
where u1.user_id = 1 and u2.user_id=2
group by title;
note: cannot tell what table title is in, or the purpose of step_taken was as step.id is identical.

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?

Compare 2 fields of table A with 6 fields of table B

I've got two tables in my MySQL DB. One contains requiredSkill1, requiredSkillLevel1, requiredSkill2, requiredSkillLevel2, requiredSkill3 and requiredSkillLevel3.
The other table has X rows per user with the following collumns: skill and level.
itemid requiredSkill1 requiredSkillLevel1 requiredSkill2 requiredSkillLevel2 requiredSkill3 requiredSkillLevel3
2410 3319 4 20211 1 NULL NULL
The other table:
userid skill level
21058 3412 4
21058 3435 2
21058 3312 4
Keep in mind, these are just examples.
I want every itemid which has matching values in requiredSkill{1-3} and requiredSkillLevel{1-3}.
Is this even possible with a single query and is this still performant, since the user table contains up to 300 rows per user and the item table has a fixed value of 6000 rows. This will be used in a web application, so I can use Ajax to load ranges of items from the database to decrease loading time.
I don't have the data set up. A SQL Fiddle would be helpful, but I think you want to approach it like this:
SELECT itemid FROM items i
INNER JOIN users u1 ON u1.skill = i.requiredSkill1 AND u1.level >= i.requiredSkillLevel1
INNER JOIN users u2 ON u2.skill = i.requiredSkill2 AND u2.level >= i.requiredSkillLevel2 AND u1.userid = u2.userid
INNER JOIN users u3 ON u3.skill = i.requiredSkill3 AND u3.level >= i.requiredSkillLevel3 AND u3.userid = u1.userid
Someone will solve this for you if you post demo data.

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?