This is the situation I'm dealing with:
I have 4 tables:
Users table:
+----+-------+
| id | name |
+----+-------+
| 1 | name1 |
| 2 | name2 |
| 3 | name3 |
+----+-------+
Assignment table:
+----+-----------------+
| id | assignment_name |
+----+-----------------+
| 11 | name1 |
| 12 | name2 |
| 13 | name3 |
+----+-----------------+
Submissions:
+----+---------------+---------+
| id | assignment_id | user_id |
+----+---------------+---------+
| 1 | 11 | 3 |
| 2 | 12 | 1 |
| 3 | 11 | 2 |
+----+---------------+---------+
Group_submissions
+----+----------------+---------+
| id | submission_id | user_id |
+----+----------------+---------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 3 | 1 |
+----+----------------+---------+
The submission table has an assignment_id to tell in which assignment the submission belongs to.
Also users can submit a group submission, where the one that does the submission goes to the submissions table, while the others go to the group_submissions table. That way it will be counted as one submission instead of being 2,3...N submission based on how many people where in the group.
How can i get the users that have submitted a submission or have participated in a group submission in a given assignment?
The result should return the user or users that have are in the submissions table or in the group_submissions table based on a assignment id
The result should look something likes this:
+----+-------+
| id | name |
+----+-------+
| 1 | name1 |
| 2 | name2 |
+----+-------+
It should basically return the user table.
This is what i have tried so far:
This only gives me the users that aren't in the submissions table but are in the group_submission
select * from users u
right join group_submissions gs on u.id = gs.student_id
right join assignment_submissions ass on gs.submission_id = ass.id
inner join assignments a on a.id = ass.assignment_id
where a.id = number
This only gives me the one user that made the submission (in the submissions table)
select * from users u
right join assignment_submissions ass on u.id= ass.student_id
right join group_submissions gs on ass.id = gs.submission_id
inner join assignments a on a.id = ass.assignment_id
where a.id = number
What should my join strategy be here? Or maybe joins are not the right option here.
NOTE: This is a MySQL database.
You could use exists:
select u.*
from users u
where
exists (
select 1
from submissions s
where s.user_id = u.id and s.assignment_id = ?
)
or exists (
select 1
from group_submissions gs
inner join submissions s on s.id = gs.submission_id
where gs.user_id = u.id and s.assignment_id = ?
)
I am thinking a union could do it. Like this
select * from
(
select u.*, assignment_id, 'assignment_submissions' as type from users u
inner join assignment_submissions ass on u.id= ass.student_id
union
select u.*, assignment_id, 'group_submissions' from users u
inner join group_submissions gs on u.id = gs.student_id
inner join assignments a on a.id = ass.assignment_id
)a
where assignment_id = ?
Related
Consider the following tables:
User Table
id | name | createdAt |
-----------------------|
1 | John | 2018-02-02 |
Activity Table
id | itemId | itemTable | createdAt |
-------------------------------------|
13 | 1 | User | 2018-02-02 |
14 | 142 | Client | 2018-02-02 |
I want to be able to LEFT JOIN on a table specified in the column:
SELECT b.*
FROM activity AS a
LEFT JOIN *a.tablename* AS b
ON b.id = a.itemid
for MemSQL or MySQL
You cannot do this in a SELECT query. SQL does not operate this way.
If you know there are only two tables, you can express the query like this:
SELECT u.*
FROM USER u
WHERE u.id = (SELECT 1 FROM activity a WHERE a.itemid = u.id)
UNION ALL
SELECT c.*
FROM client c
WHERE c.id = (SELECT 1 FROM activity a WHERE a.itemid = c.id);
I'm currently writing a ticket system that has three tables
one for users:
users
+----+-----------+----------+
| ID | FirstName | LastName |
+----+-----------+----------+
| 1 | First | User |
| 2 | Second | User |
| 3 | Third | User |
| 4 | Fourth | User |
| 5 | Fifth | User |
+----+-----------+----------+
one for tickets:
ticket
+----+---------------+
| ID | TicketSubject |
+----+---------------+
| 1 | Ticket #1 |
| 2 | Ticket #2 |
| 3 | Ticket #3 |
| 4 | Ticket #4 |
+----+---------------+
and one to assign users to tickets to action (can be more than one user per ticket):
ticket_assigned
+----+----------+--------+
| ID | TicketID | UserID |
+----+----------+--------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 3 | 5 |
| 5 | 3 | 3 |
+----+----------+--------+
I'm trying to create a summary to show each user, and how many tickets they have assigned to them, example:
+------------+-------+
| Name | Count |
+------------+-------+
| First | 2 |
| Second | 1 |
| Third | 1 |
| Fourth | 0 |
| Fifth | 1 |
| Unassigned | 2 |
+------------+-------+
Note that the last entry is "unassigned", this is the number of records in the ticket table that DONT appear in the ticket_assigned table (thus being, unassigned). Also further note that user "Fourth" is zero, in that that user has no records in the ticket_assigned table.
Here is the current MySQL query I am using:
SELECT
CASE
WHEN users.FirstName IS NULL
THEN 'Unassigned'
ELSE users.FirstName
END as 'UserName',
COUNT(*) as 'TicketCount'
FROM tickets
LEFT OUTER JOIN ticket_assigned ON tickets.ticket_id = ticket_assigned.ticket_id
LEFT OUTER JOIN users ON ticket_assigned.user_id = users.user_id
GROUP BY ticket_assigned.user_id
ORDER BY UserName;
Problem with this is that it's not showing any of the users that don't feature in the ticket_assigned table, I'm essentially getting this:
+------------+-------+
| Name | Count |
+------------+-------+
| First | 2 |
| Second | 1 |
| Third | 1 |
| Fifth | 1 |
| Unassigned | 2 |
+------------+-------+
Is anyone able to assist and tell me how I can modify my query to include users that have no records in the ticket_assigned table? Thanks in advance!
Use a LEFT JOIN with a subquery to aggregate tickets:
SELECT t1.FirstName,
COALESCE(t2.ticket_count, 0) AS num_tickets
FROM users t1
LEFT JOIN
(
SELECT UserID, COUNT(*) AS ticket_count
FROM ticket_assigned
GROUP BY UserID
) t2
ON t1.ID = t2.UserID
UNION ALL
SELECT 'Unassigned', COUNT(*)
FROM tickets t
WHERE NOT EXISTS (SELECT 1 FROM tickets_assigned ta
WHERE ta.ticketId = t.id)
In MySQL, I think you need a left join and union all:
select u.id, u.firstname, count(ta.userId) as num_tickets
from users u left join
tickets_assigned ta
on ta.userId = u.id
group by u.id, u.firstname
union all
select NULL, 'Unassigned', count(*)
from tickets t
where not exists (select 1
from tickets_assigned
where ta.ticketId = t.id
);
I included the u.id in the aggregations. I'm uncomfortable just aggregating (and reporting) by first name, because different people frequently have the same first name, even in a relatively small group.
SELECT
u2.Firstname, IFNULL(tmp.count, 0) AS count
FROM users u2
LEFT JOIN (
SELECT u.id, u.Firstname, COUNT(1) as count
FROM ticket_assigned ta
LEFT JOIN ticket t ON t.id = ta.ticketID
LEFT JOIN users u ON u.id = ta.userID
GROUP BY u.id
) tmp ON tmp.id = u2.id
UNION
SELECT
'Unassigned', count(1) AS count
FROM ticket
WHERE id NOT IN (SELECT ticketid FROM ticket_assigned)
I want to create a query for project listings that would give the number of registered applications, excluding the ones for which the user does not exist.
In this case, considering user 10 does not exist, I should have the query results as folows:
RESULTS
+----+------------+--------------+
| id | project | applications |
+----+------------+--------------+
| 1 | MyProject1 | 3 |
| 2 | MyProject2 | 0 |
| 3 | MyProject3 | 0 |
+----+------------+--------------+
TABLES
Projects
+----+------------+
| id | name |
+----+------------+
| 1 | MyProject1 |
| 2 | MyProject2 |
| 3 | MyProject3 |
+----+------------+
applications
+----+------+------------+
| id | user | project_id |
+----+------+------------+
| 1 | 3 | 1 |
| 2 | 4 | 1 |
| 3 | 5 | 1 |
| 4 | 10 | 1 |
+----+------+------------+
users
+----+---------+
| id | Name |
+----+---------+
| 1 | Smith |
| 2 | John |
| 3 | Paul |
| 4 | Chris |
| 5 | Gabriel |
+----+---------+
The below query is not excluding the non-existing users:
SELECT `projects` . * , (
SELECT COUNT( * )
FROM `applications`
WHERE `applications`.`project_id` = `projects`.`id`
AND EXISTS (
SELECT `applications`.`id`
FROM `applications` , `users`,`project`
WHERE `application`.`user` = `users`.`id` AND `applications`.`project_id` = `project`.`id`
)
) AS `applications`
FROM `projects` ORDER BY `id` DESC LIMIT 30
I think you want left join and group by:
select p.id, p.name, count(u.id)
from projects p left join
applications a
on p.id = a.project_id left join
users u
on a.user_id = u.id
group by p.id, p.name;
However, you might want to think about fixing the data. It seems like there should be foreign key relationships between applications and projects and applications and users. The ability to have an invalid user means that there is no valid foreign key relationship to users.
Your query looks overly complicated. This should do:
select
id,
name as project,
(
select count(*)
from applications a
where a.project_id = p.id
and a.user in (select id from users)
) as applications
from projects p;
Based on previous solution
select p.id, p.name, count(u.id)
from projects p left join
applications a
on p.id = a.project_id left join
users u
on a.user = u.id
where u.id is not null
group by p.id, p.name;
When you do a left join, if the search value doesn't exists, it returns null. Then filtering by excluding null users, will give you the result.
Please find a sqlfiddle to illustrate it : http://www.sqlfiddle.com/#!9/cbfec6/3
But easiest solution would be
select p.id, p.name, count(u.id)
from projects p,applications a, users u
where a.user = u.id
and p.id = a.project_id
group by p.id, p.name;
I have small trouble creating a query. I have two tables:
user_data
+----+---------+--------+
| id | mail | etc... |
+----+---------+--------+
| 1 | 1#m.com | ... |
| 2 | 2#m.com | ... |
| 3 | 3#m.com | ... |
+----+---------+--------+
contracts
+----+---------+--------+
| id | user_id | etc... |
+----+---------+--------+
| 1 | 1 | ... |
| 2 | 2 | ... |
| 3 | 1 | ... |
| 4 | 1 | ... |
| 5 | 3 | ... |
+----+---------+--------+
As you can see, the first table contains data about users and the secound one about their contracts. There will be always only one entry about a user, but a user can have multiple contracts. Now I need to find out
all users, theirs first contract id ( with the lowest id in contracts table ) and their email, if it's in the were parameters.
So far I have such query:
SELECT
u.id as user_id,
c.id as first_contract_id,
u.mail as email
FROM
user_data u
JOIN
contracts c ON u.id = c.user_id
WHERE
u.mail
IN (
'1#me.com',
'2#me.com',
'3#me.com'
);
Now I have no idea how I can select only the lowest contract ID from these results. Help apreciated.
SELECT
u.id as user_id,
min(c.id) as first_contract_id,
u.Mail as email
FROM
user_data u
JOIN
contracts c ON u.id = c.user_id
WHERE
u.mail IN ('1#me.com', '2#me.com', '3#me.com')
GROUP BY u.id
If you group by the user you can get the lowest contract by using min.
(And MySQL has no problem with selecting column that are not in a group)
select
u.id as user_id,
c.id as first_contract_id,
u.Mail as email
from users as u inner join
(
select min(id) as id,user_id from contracts
group by user_id
) as c
on u.id = c.user_id
WHERE
u.mail
IN (
'1#me.com',
'2#me.com',
'3#me.com'
);
I'm currently trying to write a query which involves 5 main tables, 2 of which are referring to a 3rd with foreign keys, but not relating to each-other... and one of the first 2 tables is the main subject of the query. Here's a basic synopsis.
instance user
-------- ----
id id
name name
user_id
def def_map
--- ------
id id
name instance_id
user_id def_id
def_data
--------
id
name
def_id
user_id
What I want to do is get a list of all of the 'def_map's for a single user. In each row I'd like the associated def_data to be displayed as well. So the rows would be like:
instance.id, def.id, def.name, def_data.name, user.id
I can figure out how to get all info except def_data.name in the result, or all info except for instance.id ... but can't figure out how to get then all together using one query. Is it possible? I think part of the problem is I don't know if there is a special word that describes this type of query so I would know what to read up on.
I'm using DQL, but examples in SQL would be just as useful. Thanks in advance for any help.
If you can pull the data individually using 2 queries you simply need to UNION them together
SELECT user.id, i.id, d.id, dd.name
FROM user u
INNER JOIN instance i ON u.id=i.user_id
INNER JOIN def d ON dm.user_id = u.id
INNER JOIN def_data dd ON dd.def_id = d.id
UNION ALL
SELECT u.id, i.id AS instance_id, d.id, dd.name
FROM instance i
INNER JOIN user u ON u.id=i.user_id
INNER JOIN defmap dm ON dm.instance_id=i.id
INNER JOIN def_data dd ON dd.def_id=dm.def_id
select I.id, D.id, D.name, DD.name, U.id
from user U inner join instance I on I.user_id = U.id
Inner join def D on D.user_id = U.id
inner join def_map DM on DM.def_id = D.id AND I.id = DM.instance_id
inner join def_data DD on DD.def_id = D.id AND U.id = DD.user_id
Test data:
USER
+----+-------------------------+
| id | name |
+----+-------------------------+
| 1 | Name1 |
+----+-------------------------+
Instance
+----+------+---------+
| id | name | user_id |
+----+------+---------+
| 1 | I1 | 1 |
+----+------+---------+
def_map
+--------+-------------+--------+
| id | instance_id | def_id |
+--------+-------------+--------+
| 1 | 1 | 1 |
+--------+-------------+--------+
def
+--------------+------+
| id | name | user_id |
+--------------+------+
| 1 | df1 | 1 |
+--------------+------+
def_data
+--------+------+--------+---------+
| id | name | def_id | user_id |
+--------+------+--------+---------+
| 1 | dd1 | 1 | 1 |
+--------+------+--------+---------+
Result
+-------------+--------+----------+---------------+---------+
| instance.id | def.id | def.name | def_data.name | user.id |
+-------------+--------+----------+---------------+---------+
| 1 | 1 | df1 | dd1 | 1 |
+-------------+--------+----------+---------------+---------+