Left Join with conditional on Right Table - mysql

I'm having trouble figuring out the sql for the following problem of mine. I have two tables like this:
+----------+------------+------------+
| event_id | event_name | event_date |
+----------+------------+------------+
+---------------+----------+---------+--------+
| attendance_id | event_id | user_id | status |
+---------------+----------+---------+--------+
What I am trying to do is to get a table like this:
+----------+--------+
| event_id | status |
+----------+--------+
Where the conditional for the second attendance table is the user_id. I'm trying to get a list of all the events as well as the status of a user for each one of those events, even if there is no record inside attendance (NULL is ok for now). And again, the status data from the attendance table needs to be chosen by the user_id.
From my initial research, I thought this would work:
SELECT event_id, status FROM events LEFT JOIN attendance WHERE attendance.user_id='someoutsideinput' ORDER BY event_date ASC
But that is not working for me as expected..how should I go about this?
Thanks!

all you need to do is to move the condition in the WHERE clause into ON clause.
SELECT events.event_id, COALESCE(attendance.status, 0) status
FROM events LEFT JOIN attendance
ON events.event_id = attendance.event_id AND
attendance.user_id='someoutsideinput'
ORDER BY events.event_date ASC

You need to more that condition to the JOIN clause instead of the WHERE clause.
BTW, you have not specified the join criteria between the tables, I have also corrected that below.
SELECT E.event_id
,A.status
FROM events E
LEFT JOIN
attendance A
ON E.event_id = A.event_id
AND A.user_id='someoutsideinput'
ORDER BY
E.event_date ASC

Related

how to get GROUP data from multiple tables msSQL

tblDailyProduction
+---------+------------+------------+------------+----------+----------+
| date | items | quantity| weight| wheatConsumed| |
+---------+------------+------------+------------+----------+----------+
tblCashBillbook
+---------+------------+------------+------------+----------+----------+
+---------+------------+------------+------------+----------+----------+
| date | bagWeight | totalBags |
+---------+------------+------------+------------+----------+----------+
SELECT CAST(tblDailyProduction.date AS DATE) as DateField,
SUM(tblDailyProduction.quantity * tblDailyProduction.weight)
AS totalProduct,SUM(tblCashBillbook.totalBags * tblCashBillbook.bagWeight)
AS totalIssued
FROM tblDailyProduction
left join tblCashBillbook on tblDailyProduction.date=tblCashBillbook.date
GROUP BY CAST(tblDailyProduction.date AS DATE)
I want to Group data according to the date from two different tables using a JOIN clause. Getting the data from tblDailyProduction table but NULL from the tblCashBillBook table.
tried INNER, LEFT and RIGHT joins but there is a problem with the GROUP BY clause.
You don't need to group by both dates, as the dates are put together in your join statement.
Try changing it to:
GROUP BY dateField
What might be causing some problem is that you are doing a left join, so not every row will have a tblCashBillbook.date value. If they do, you shouldn't be using a left join but an inner join. So, you are trying to group by something that might be null in some rows, so again, I suggest you just group by the tblDailyProduction date column.

Count the number of exists and not exist using MySQL

I am trying to list out all task with the count of finished/completed task (In submissions). The problem is that I also want to show all task that no users have finished. This query does not list out count = 0 (Null). Is there any way to do this?
Wanted result:
Date | title | completed
2014-05-20 | Case 1 | 45
2014-05-24 | Case 10 | 11
2014-05-20 | Case 2 | 0
I have tried so far:
Select date, title, count(*) as completed
from users u, submissions s, task t
where u.userPK = s.user
and s.task= t.taskPK
group by taskPK
order by completed desc;
You need to use an OUTER JOIN to get your desired results. However, considering the previous answer didn't suffice, I would also guess you don't want to GROUP BY the taskPK field, but rather by the date and title fields.
Perhaps this is what you're looking for:
SELECT t.date, t.title, count(*) cnt
FROM task t
LEFT JOIN submissions s ON t.task = s.taskPK
GROUP BY t.date, t.title
ORDER BY cnt DESC
I also removed the user table as I'm not sure how it affects the results. If you need it back, just add an additional join.
I think you should be able to achive this using a LEFT JOIN:
SELECT date, title, COUNT(u.userPK) completed FROM task t
LEFT JOIN submissions s ON s.task = t.taskPK
LEFT JOIN users u ON s.user = u.userPK
GROUP BY t.taskPK
ORDER BY completed;

In MySQL, how can I get an aggregate function to return 0 after a where clause and a group by?

I have a table of users and a table of time-entries. I am trying to obtain the sum(time_entry.hours_worked) per employee where the date is within a range of values.
With:
SELECT employee.id, COALESCE(SUM(time_entry.hours_worked),0) as `sum`
FROM employee
LEFT JOIN time_entry
ON employee.id = time_entry.student_id
GROUP BY employee.id;
I am able to obtain entries for all employees, even if no hours are worked :
+----+--------+
| id | sum |
+----+--------+
| 1 | 191.00 |
| 2 | 48.00 |
| 3 | 0.00 |
+----+--------+
With a where statement:
SELECT employee.id, COALESCE(SUM(time_entry.hours_worked),0) AS `sum`
FROM employee
LEFT JOIN time_entry
ON employee.id = time_entry.student_id
WHERE time_entry.date < 1367798400
GROUP BY employee.id;
I obtain an empty set. How can I use the WHERE statement and still obtain 0 per employee when no entries are found in the database?
The problem is that the condition is on the second table in the left outer join. When there is no match, all the columns are set to NULL. So, the where clause fails. In fact, such a condition is turning the left outer join back into an inner join.
To fix this, move the condition to the on clause:
SELECT employee.id, COALESCE(SUM(time_entry.hours_worked),0) AS `sum`
FROM employee
LEFT JOIN time_entry
ON employee.id = time_entry.student_id and
time_entry.date < 1367798400
GROUP BY employee.id;

MySQL select distinct across multiple tables

I have a query that selects all columns from multiple tables, but it's returning multiples of the same values (I only want distinct values).
How can I incorporate something like this? When I try this, it still
Select Distinct A.*, B.*, C.*....
Does distinct only work when selecting the column names and not all (*) ? In this reference it says distinct in reference to column names, not across all of the tables. Is there any way that I can do this?
edit - I added more info below
Sorry guys, I just got back onto my computer. Also, I just realized that my query itself is the issue, and Distinct has nothing to do with it.
So, the overall goal of my Query is to do the following
Generate a list of friends that a user has
Go through the friends and check their activities (posting, adding friends, etc..)
Display a list of friends and their activities sorted by date (I guess like a facebook wall kind of deal).
Here are my tables
update_id | update | userid | timestamp //updates table
post_id | post | userid | timestamp //posts table
user_1 | user_2 | status | timestamp //friends table
Here is my query
SELECT U.* , P.* ,F.* FROM posts AS P
JOIN updates AS U ON P.userid = U.userid
JOIN friends AS F ON P.userid = F.user_2 or F.user_1
WHERE P.userid IN (
select user_1 from friends where user_2 = '1'
union
select user_2 from friends where user_1 = '1'
union
select userid from org_members where org_id = '1'
union
select org_id from org_members where userid = '1'
)
ORDER BY P.timestamp, U.timestamp, F.timestamp limit 30
The issue I'm having with this (that I thought was related to distinct), is that if values are found to meet the requirements in, say table Friends, a value for the Posts table will appear too. This means when I'm displaying the output of the SQL statement, it appears as if the Posts value is shown multiple times, when the actual values I'm looking for are also displayed
The output will appear something like this (notice difference between post value in the rows)
update_id | update | userid | timestamp | post_id | post | userid | timestamp | user_1 | user_2 | status | timestamp
1 | update1 | 1 | 02/01/2013 | 1 | post1| 1 | 2/02/2013| 1 | 2 | 1 | 01/30/2013
1 | update1 | 1 | 02/01/2013 | 2 | post2| 1 | 2/03/2013| 1 | 2 | 1 | 01/30/2013
So, as you can see, I thought I was having a distinct issue (because update1 appeared both times), but the query actually just selects all the values regardless. I get the results I'm looking for in the Post table, but all the other values are returned. So, when I display the table in PHP/HTML, the Post value will display, but I also get duplicates of the updates (just for this example)
When you select distinct *, you select every row, including the one that makes the record unique. If you want something better than what you are getting, you have to type the individual column names in your select clause.
It would be easy if you explain a little more what is the connection between the tables you'r querying, because you can use joins, unions (as mentioned above) or even group by's ...
Your updated post shows one of the JOIN conditions as:
JOIN friends AS F ON P.userid = F.user_2 OR F.user_1
This is equivalent to:
JOIN friends AS F ON (P.userid = F.user_2 OR F.user_1 != 0)
and will include many rows that you did not intend to include.
You probably intended:
JOIN friends AS F ON (P.userid = F.user_2 OR P.userid = F.user_1)
I think you want this:
select *
from tableA
union
select *
from tableB
union
select *
from tableC
This assumes that HHS tables all have the same number of columns and they are of the same data type. This not, you'll have to select specific columns to make it so.

How to count the number of instances of each foreign-key ID in a table?

Here's my simple SQL question...
I have two tables:
Books
-------------------------------------------------------
| book_id | author | genre | price | publication_date |
-------------------------------------------------------
Orders
------------------------------------
| order_id | customer_id | book_id |
------------------------------------
I'd like to create a query that returns:
--------------------------------------------------------------------------
| book_id | author | genre | price | publication_date | number_of_orders |
--------------------------------------------------------------------------
In other words, return every column for ALL rows in the Books table, along with a calculated column named 'number_of_orders' that counts the number of times each book appears in the Orders table. (If a book does not occur in the orders table, the book should be listed in the result set, but "number_of_orders" should be zero.
So far, I've come up with this:
SELECT
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date,
count(*) as number_of_orders
from books
left join orders
on (books.book_id = orders.book_id)
group by
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date
That's almost right, but not quite, because "number_of_orders" will be 1 even if a book is never listed in the Orders table. Moreover, given my lack of knowledge of SQL, I'm sure this query is very inefficient.
What's the right way to write this query? (For what it's worth, this needs to work on MySQL, so I can't use any other vendor-specific features).
Your query is almost right and it's the right way to do that (and the most efficient)
SELECT books.*, count(orders.book_id) as number_of_orders
from books
left join orders
on (books.book_id = orders.book_id)
group by
books.book_id
COUNT(*) could include NULL values in the count because it counts all the rows, while COUNT(orders.book_id) does not because it ignores NULL values in the given field.
SELECT b.book_id,
b.author,
b.genre,
b.price,
b.publication_date,
coalesce(oc.Count, 0) as number_of_orders
from books b
left join (
select book_id, count(*) as Count
from Order
group by book_id
) oc on (b.book_id = oc.book_id)
Change count(*) to count(orders.book_id)
You're counting the wrong thing. You want to count the non-null book_id's.
SELECT
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date,
count(orders.book_id) as number_of_orders
from books
left join orders
on (books.book_id = orders.book_id)
group by
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date
select author.aname,count(book.author_id) as "number_of_books"
from author
left join book
on(author.author_id=book.author_id)
GROUP BY author.aname;