MySQL: Find users with no submission - mysql

I'm struggling a little bit with a query and hope you can help.
I have two tables. On with all the users and one with information from submitted forms.
Both contain the user ID.
What I would need to find out is which user from the users table does not appear on the report table.
This is what I have so far:
SELECT u.ID, u.display_name, u.user_email, r.user_id
FROM users AS u
LEFT JOIN report AS r ON u.ID = r.user_id
WHERE NOT EXISTS(
SELECT *
FROM report AS rr
WHERE u.ID = rr.user_id
)
This seems to be fine for the users who absolutely have never submitted the form.
But the reports table also contains a date column and I was wondering how I can get this grouped by day.
In the front end then I will hopefully have a table which shows:
date: user:
2015-01-01 user a
2015-01-01 user f
2015-01-02 user g
2015-01-02 user a
2015-01-03 user z
2015-01-03 user x
Where the users are those who have not submitted the form that day.
Hope you can help. Thank in advance!

If you want to get a list of users that doesn't have any rows in the report table then you can generate a set that is the Cartesian product of the users and the dates that are present in the report table, and then do a left join with that set and check for null.
The Cartesian set formed by the cross join will contain all possible combinations of dates and users; that is would the report table would contain is all users had added reports on all available dates.
select r.date, u.user_id
from report r
cross join users u
left join (select r.date, r.user_id from users as u join report as r on u.id = r.user_id)
a on a.date = r.date and a.user_id = u.user_id
where a.date is null
Sample SQL Fiddle
With most other databases this could have been done with a set difference operator (minus or except) instead of a left join.

I'm making assumptions about column names in your report table for this answer:
SELECT x.report_date, u.user_id, u.display_name
FROM users u
JOIN (
SELECT DISTINCT report_date
FROM reports
) x
LEFT JOIN reports r
ON r.user_id = u.user_id
AND r.report_date = x.report_date
WHERE r.report_date IS NULL
ORDER BY x.report_date, u.user_id
Check out this fiddle: http://sqlfiddle.com/#!9/407ac/5

Left outer join with where clause...
Here is a good link ...
http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
SELECT * FROM `users`
LEFT OUTER JOIN `report`
ON `users`.`ID` = `report`.`user_id`
WHERE `report`.`user_id` IS null
ORDER BY `report`.`Date`

Surely you could just pass in the date you wanted to check?
so something like this (using #reportDate as the parameter):
SELECT * FROM users
LEFT OUTER JOIN report
ON users.ID = report.user_id
WHERE report.user_id IS NULL
AND report.Date = #reportDate

You can get the pairs of users/dates without reports. Generate all possible rows using a cross join and then filter out the ones that exist:
select u.*, r.date
from users u cross join
(select distinct date from reports r) d left join
reports r
on u.id = r.user_id and d.date = r.date
where r.userid is null;

Related

Get data even if one row is NULL

I have this query to get users from the users table and also get the latest time (a timestamp) from the logs table where the entry is "login_ok". This is intended to show a list of users and the last time them logged in.
SELECT u.`id`, u.`email`, u.`firstname`, u.`lastname`, u.`type`, u.`creation_date`, MAX(l.`time`) as `last_login`
FROM `users` AS u
JOIN `logs` AS l ON u.id = l.user_id
WHERE l.`action` = 'login_ok'
AND `visible` = 1
GROUP BY u.`id`
ORDER BY u.`id` ASC
My issue here is: if the user has never logged in, the "login_ok" entry doesn't exists for that user, so the query cannot get that user data.
Is there any way to get all user data even if the l.time on logs doesn't exist? I tried with JOINname_admin_users_logAS l ON (l.timeIS NOT NULL AND u.id = l.user_id) but still not showing that new user without login log.
Use a LEFT JOIN instead of a regular JOIN (which actually means INNER JOIN), and move the filter on action = 'login_ok' to that LEFT JOIN clause.
NB : from your query we cannot tell from which table the visible column comes from, so I assumed it is related to users...
SELECT
u.id,
u.email,
u.firstname,
u.lastname,
u.type,
u.creation_date,
MAX(l.time) as last_login
FROM users AS u
LEFT JOIN logs AS l
ON u.id = l.user_id and l.action = 'login_ok'
WHERE u.visible = 1
GROUP BY u.id
ORDER BY u.id ASC
Use a left join:
SELECT u.`id`, u.`email`, u.`firstname`, u.`lastname`, u.`type`, u.`creation_date`, MAX(l.`time`) as `last_login`
FROM `users` u LEFT JOIN
`logs` l
ON u.id = l.user_id AND l.`action` = 'login_ok'
WHERE u.`visible` = 1
GROUP BY u.`id`
ORDER BY u.`id` ASC;
This assumes that visible is in users. If it is in logs, then that condition should also be in the ON clause.
You can simply ignore the login_ok and search for all values of l.action.
But if you want only values with login_ok and null then you can do:
WHERE l.`action` = 'login_ok' OR l.`action` is null
You should use LEFT/RIGHT joins instead of JOIN(inner)
For example:
SELECT u.id, u.name, l.time
FROM users u LEFT JOIN logs l
ON u.id=l.user_id
In this case you'll get ALL the records from 'users'(the table on the left in the select: users - left, logs - right) and all records from the right('logs') table for which condition u.id=l.user_id is true.
Finally you'll get something like this:
u.id u.name l.time
1 John 10.00am
2 Mary 2.15pm
3 Mark null

Making a query with several JOINS

I am stuck with some SQL query.
I have four tables. Which are connected:
user =>user_account=>acount_profile_entries=>profile_entries
From left to right they are one to many.
user_account has a user_id field as FK.
account_profile_field has user_account_id and profile_entry_id.
Profile_entries has a text field that I need to show for each user (account).
I need to write a query that will show me, all accounts for every user, and its profile entries.
I am sorry if this is confusing, I tried to make it simple
This is what I have done so far. I can show all accounts for every user and this is the point I am stuck with. Last two commented out Joins are not working properly. I believe I am close somewhat, I just need a push :)
SELECT
u.email AS Email,
u.id AS UserId,
ua.id AS UserAccountId,
ua.app_id AS Application
FROM users AS u
INNER JOIN user_accounts ua ON ua.user_id = u.id
-- INNER JOIN account_profile_entries ape ON ape.user_account_id = ua.id
-- INNER JOIN profile_entries as pe ON pe.id = ape.profile_entry_id
limit 10
Try this SQL Query with using LEFT JOIN
Description :- The MySQL LEFT JOIN joins two tables and fetches rows based on a condition, which is matching in both the tables and the unmatched rows will also be available from the table written before the JOIN clause.
SYNTAX
SELECT column_name(s)
FROM table1
LEFT JOIN table2 ON table1.column_name = table2.column_name;
SELECT u.*,
u.id AS UserId,
ua.id AS UserAccountId,
ua.app_id AS Application,pe.* FROM `users` u
LEFT JOIN user_accounts ua ON ua.user_id = u.id
LEFT JOIN account_profile_entries ape ON ape.user_account_id = ua.id
LEFT JOIN profile_entries as pe ON pe.id = ape.profile_entry_id LIMIT 10

Sql count returns wrong numbers

i have an api which i make calls to and i need alot of data from different tables so i use joins on them, now the problem is that whilst i have 4 replies, and 5 interactions the data always returns 20 replies and 20 interactions this is the result:
screen_name screen_state replies interactions alerts
sjerd 0 20 20 0
i use this query to count the records and results:
SELECT u.screen_name,
u.screen_state,
count(r.id) AS replies,
count(i.id) AS interactions,
count(a.alerts) AS alerts
FROM users u
LEFT JOIN reply r ON u.id = r.user
LEFT JOIN interactions i ON u.id = i.user_id
LEFT JOIN alerts a ON u.id = a.user_id WHERE u.id ='2'
GROUP BY u.id, u.screen_state
can someone see why it's returning 20 while i only have 7 rows of replies in total in reply table,
and 5 rows of interactions in total in interaction table.
each row is 1 reaction or reply.
Your counts are always going to give the same result as all tables are joined at the same level.
You need to do your counts as inline sub-queries (or whatever - I can never remember the correct terminology):
SELECT u.screen_name,
u.screen_state,
(select count(*) from reply r where u.id = r.user) AS replies,
(select count(*) from interactions i where u.id = i.user_id) AS interactions,
(select count(*) from alerts a where u.id = a.user_id) AS alerts
FROM users u
WHERE u.id ='2'
SELECT u.screen_name, u.screen_state,
count(DISTINCT r.id) AS replies,
count(DISTINCT i.id) AS interactions,
count(DISTINCT a.alerts) AS alerts
FROM users u
LEFT JOIN reply r ON u.id = r.user
LEFT JOIN interactions i ON u.id = i.user_id
LEFT JOIN alerts a ON u.id = a.user_id WHERE u.id ='2'
GROUP BY u.id, u.screen_state

Select Two Values Based Off Same Column

I am trying to select two usernames in one row of a query one would be called 'username' and the second one say 'username2'. This is the code I have atm. The users table uses a primary key of user_id.
SELECT
r.report_id,
r.poster_id,
r.reporter_id,
u.username,
(2nd username)
FROM reports r,
users u
WHERE r.report_id = :report_id
AND r.reporter_id = u.user_id
AND r.poster_id = u.user_id
you need to join the table user twice
SELECT
r.report_id,
r.poster_id,
r.reporter_id,
u.username AS ReporterName,
b.userName as PosterName
FROM
reports r
INNER JOIN users u
ON r.reporter_id=u.user_id
INNER JOIN users b
ON r.poster_id=b.user_id
WHERE
r.report_id=:report_id
Here is the code for MySQL
SELECT
r.report_id,
r.poster_id,
r.reporter_id,
u.username,
u.username username2,
FROM reports r,
users u
WHERE r.report_id = :report_id
AND r.reporter_id = u.user_id
AND r.poster_id = u.user_id

How to get good results from DB

i have a problem with sql query.
I need to get list of users. The problem is the left join i use.
this is my query
SELECT
u.*
FROM
users u LEFT JOIN game g on g.user_id = u.user_id
LEFT JOIN game_actions ga on ga.game_id = g.id
LEFT JOIN emails e on e.id = ga.email_id
WHERE
u.user_id = 0
AND u.is_contact_by_email = 1
AND email.type = 2
this query returns the same user more then once because of the join with other tables
i want this query to return each user just one time.
i'm using sql developer.
thanks in advanced.
Given that you're not using game, game_actions, or emails for any purpose (they're not filtering users, and you're not enriching the results with data from either of these tables), there's no need to join those tables at all:
SELECT
u.*
FROM users u
WHERE u.user_id = 0
AND u.is_contact_by_email = 1
You may group result by user_id and use aggregate functions to return other fields, for eaxmple -
SELECT u.user_id, GROUP_CONCAT(g.game_id) games FROM users u
LEFT JOIN game g
ON g.user_id = u.user_id
LEFT JOIN game_actions ga
ON ga.game_id = g.id
LEFT JOIN emails e
ON e.id = ga.email_id
WHERE
u.user_id = 0 AND u.is_contact_by_email = 1
GROUP BY
u.user_id
I suppose there are more games, actions, and emails for each user. How do you imagine the result table to look like? Because when you are selecting only from user table (SELECT u.*), then there is no point in joining others. If you need the other tables, use GROUP BY (u.user_id) to group rows by user.
Try to use keyword distinct with your query