I am using a system I didn't create. The system has 3 main tables:
users, courses, and usergroups. I am using an extra table called coursehits.
It's a MySQL DB, 5.0. There aren't any relationships in the DB, so users are assigned to courses by simply adding an entry to usergroups (course_id and user_id) from the courses and users table. Likewise if they start a course an entry is made to coursehits.
I am trying to count the number of users in coursehits and usergroups for reporting data. So far I have the following which doesn't count correctly in one query but this doesn't count correctly, the results are much too high:
SELECT DISTINCT
c.course_name,
COUNT(ug.user_id) AS "Enrolled",
COUNT(ch.user_id) as "Started"
FROM courses c, usergroups ug, coursehits ch, users u
WHERE ch.user_id = u.id
AND ug.user_id = u.id
AND ug.course_id = c.id
AND ch.page_id != 4
GROUP BY 1
Before I was doing the following individually which does work:
SELECT DISTINCT c.course_name, COUNT(ug.user_id) AS "Enrolled"
FROM courses c, usergroups ug
WHERE ug.course_id = c.id
GROUP BY 1
Where as now I am trying to report the status of users for each course on one query, I hope that makes sense?!?
Try:
SELECT c.course_name,
COUNT(DISTINCT ug.user_id) AS "Enrolled",
COUNT(DISTINCT ch.user_id) as "Started"
FROM courses c
left join usergroups ug on ug.course_id = c.id
left join coursehits ch on ch.course_id = c.id and ch.page_id != 4
GROUP BY c.course_name
Related
I'm developing an attendance system but i'm stuck.
I have 3 tables: users, attendance_schedules and marks
users has: id, first_name, group_name, status etc columns.
attendance_schedules has: group_name, meeting_date etc columns. this table stores information about upcoming meetings
marks has: user_id, meeting_date, status etc columns. This stores a marked attendance
On the day of a meeting attendance_schedules.meeting_date, I want to display all the users that belong to the same group. However, when a user is marked, it should change the button to marked (i am using marked.status to check if it is marked)
The challenge is, when a user is marked, it displays the user twice - one for marking and the other is marked. Seems database is returning the same user (marked and unmarked)
SELECT u.first_name, m.meeting_date
FROM users AS u
LEFT JOIN marks AS m
ON u.id = m.user_id
WHERE u.status = 1
AND u.meeting_group = 'servicon'
I also tried
SELECT u.first_name, m.meeting_date
FROM users AS u
LEFT JOIN marks AS m
ON u.id = m.user_id
WHERE u.status = 1
AND u.meeting_group = 'servicon'
AND m.meeting_date = '2023-02-01'
I also tried joining the three tables but it still didnt work
Try using Select Distinct:
SELECT Distinct u.first_name, m.meeting_date
FROM users AS u
LEFT JOIN marks AS m
ON u.id = m.user_id
WHERE u.status = 1
AND u.meeting_group = 'servicon'
I have 4 tables, three are many to many relationship:
Student(StudID,GroupId,Name,....)
Lesson(LessID,LessonName,Mark)
StudentLesson(StudID,LessID)
and the relationship between student and Group is One to Many
Student(StudID,Name,....)
Group(GroupId,GroupNumber)
What I want is how select Name, LessonName, Mark, GroupNumber
select S.Name, L.LessonName, L.Mark, G.GroupNumber from Student s
join StudentLesson SL on SL.StudId = S.StudId
join Lesson L on SL.LessID = L.LessID
Join Group G on G.GroupId = S.GroupId
I think the error in this line Join Group G on G.GroupId=S.GroupId, because when I omit it, it works between many to many but between one to many it didn't work.
group is a reserved word, so it needs to be quoted. In MySQL, you can use backticks:
select S.Name, L.LessonName, L.Mark, G.GroupNumber
from Student S
join StudentLesson SL on SL.StudId = S.StudId
join Lesson L on SL.LessID = L.LessID
Join `Group` G on G.GroupId = S.GroupId
Based on Comments: the query is fine; you lack data that matches the results you're after.
There are no students with a groupID
There are no students with a groupID matching GROUPID in the group table.
To prove this out you could simply make the last join a LEFT Join provided you have no where clause with limits on Group.
FROM:
select S.Name,L.LessonName,L.Mark,G.GroupNumber from Student s
join StudentLesson SL on SL.StudId=S.StudId
join Lesson L on SL.LessID =L.LessID
Join Group G on G.GroupId=S.GroupId
TO:
SELECT S.Name, L.LessonName, L.Mark, G.GroupNumber
FROM Student s
INNER JOIN StudentLesson SL on SL.StudId=S.StudId
INNER JOIN Lesson L on SL.LessID =L.LessID
LEFT JOIN Group G on G.GroupId=S.GroupId
This will show you all students w/ lessons and groupNumber if the groupID's match; but i'm betting they will all be NULL.
So are you after all students regardless if they have lessons or groups if so your inner joins should be left. If you're only after students that have lessons and belong to groups then they all need to be inner joins. Just depends on what you're after!
Left join will say include all records from the prior data joins, and only those that match from this join (to group in the example)
Given the following schema:
users (id, name)
courses (id, title)
training_group (id, title)
training_group_courses (training_group_id, course_id)
users_courses (user_id, course_id)
users_training_groups (user_id, training_group_id)
User has many courses (individually assigned)
User has many courses through training_groups, which have many courses
I want to retrieve a set of course titles for a particular user id that includes inidividually assigned courses (from users_courses) as well as through the users training groups relation (users_training_groups)
I can do this by running multiple queries and assembling results in a programming language, but I haven't been able to come up with a single SQL query that can do the same.
One way would be to use two different queries and join the result using the union operator:
select c.title, 'individual' as source from users u
join users_courses uc on u.id = uc.user_id
join courses c on c.id = uc.course_id
where u.id = 1
union all
select c.title, 'group' as source from users u
join users_training_groups ugt on ugt.user_id = u.id
join training_group tg on ugt.training_group_id = tg.id
join training_group_courses tgc on ugt.training_group_id = tgc.training_group_id
join courses c on c.id = tgc.course_id
where u.id = 1
Good day, I can't seem to figure out how to do this. I'll first explain my database model:
User (user_id, name)
Job (job_id, name)
UserTopJob (user_id, job_id)
UserOtherJob(user_id, job_id)
A user can setup his top jobs which he likes best. Those values will be saved into UserTopJob by the user_id and the job_id. The user can set some other jobs he likes into UserOtherJob as well.
Now, what I want to do is query out users that match my job search input.
For example, the search input is job_id 1 and 2.
Now I want to query out the users that match BOTH job_id 1 and job_id 2, but it doesn't matter whether they are in the users top or other jobs, or divided between those two tables.
So a user must be returned if:
Both job_id 1 & 2 are in top jobs
Both job_id 1 & 2 are in the other jobs
They have both job_id 1 and 2 but in different tables
The number of input ids can grow and does not have a limit. It must always match ALL input values.
Edit: So, for example if I'm putting job_ids 1 and 2 and 3 into the query, the ids 1 AND 2 AND 3 need to be in the top or other table for that user.
Can anybody please help me create a MySQL-query that can do this and doesn't put too much pressure on db-performance?
Thanks in advance for helping me out here!
You can use UNION for this type of work.
SELECT user_id AS user FROM UserTopJob where job_id in {job_ids}
UNION
SELECT user_id AS user FROM UserOtherJob where job_id in {job_ids};
Try this query:
SELECT u.*
FROM User u
WHERE NOT EXISTS (
SELECT 1
FROM User u0
JOIN Job j ON j.job_id IN (1,2) -- or other list of job ids
LEFT JOIN UserTopJob utj ON utj.user_id = u0.user_id AND utj.job_id = j.job_id
LEFT JOIN UserOtherJob uoj ON uoj.user_id = u0.user_id AND uoj.job_id = j.job_id
WHERE u0.user_id = u.user_id
AND utj.job_id IS NULL
AND uoj.job_id IS NULL
)
Test in on SQL Fiddle
You can do a JOIN between the tables to get the required result like
select u.name as user_name,
j.name as job_name
from `user` u
INNER join usertopjob utj on u.user_id = utj.user_id
inner join userotherjob uoj on u.user_id = uoj.user_id
inner join job j on j.job_id = utj.job_id or j.job_id = uoj.job_id
where j.job_id in (1,2);
Alright, this was a brain buster this evening. Toying around with this for some time I came up with this and it seems to work.
SELECT user_id, SUM(matched) AS totalMatched FROM
(
SELECT uoj.user_id, COUNT(uoj.job_id) AS matched FROM userOtherJob AS uoj
INNER JOIN user AS u ON u.user_id = uoj.user_id
WHERE uoj.job_id IN (1,2)
GROUP BY u.user_id
UNION ALL
SELECT utj.user_id, COUNT(utj.job_id) AS matched FROM userTopJob AS utj
INNER JOIN user AS u ON u.user_id = utj.user_id
WHERE utj.job_id IN (1,2)
GROUP BY u.user_id
) AS t
GROUP BY user_id
HAVING totalMatched = 2
This query counts the matches in the 'other' table, after that the matches in the 'top' table, and sums the totals of both tables. So, the total number of matches (combined from top and other) must be the same value as the number of jobs we're looking for.
How can I get the name of students by using the section and year_level as arguments? Below is the ERD of my database.
select u.fname
from users u
join students s on u.user_id = s.user_id
join sections sec on s.section_id = sec.section_id
where sec.section_id = 1
and sec.year_level_section = 1
You don't even need to join level table. Actually, you don't need that table at all.