How do you substitute group by's with left joins? - mysql

I wrote this code:
SELECT DISTINCT c.deptid Dept,
c.id Course,
t.startdate
FROM course c
LEFT JOIN section s
ON courseid = c.id
LEFT JOIN term t
ON termid = t.id
AND t.startdate < '2011-4-1'
GROUP BY course
HAVING t.startdate IS NULL
ORDER BY dept,
course;
and I need to get rid of the group by and aggregate functions by using only join or left join. The left join is creating an extra null row and I don't know how to account for that without group by. Any help on re-writing this would be greatly appreciated.
EDIT: This code works. That is not the issue. The issue is I am not allowed to use a group by or any aggregate functions.

I am not sure if this fixes your problem, but this what your query should look like:
SELECT c.deptId as Dept, c.id as Course, startDate
FROM Course c LEFT JOIN
Section s
ON courseId = c.id LEFT JOIN
Term t
ON termId = t.id AND startDate < '2011-04-01'
WHERE startDate IS NULL
GROUP BY course
ORDER BY Dept, Course;
Here are the changes:
The distinct is unnecessary because you are doing a group by
The dates are in YYYY-MM-DD format (an ISO standard)
The comparison for NULL date is moved to a where clause
The group by statement uses the id column for course
The column aliases are introduced by as (for readability)

You shouldn't have a group by clause and your having clause should be a where clause. Try this:
SELECT DISTINCT c.deptid Dept,
c.id Course,
t.startdate
FROM course c
LEFT JOIN section s
ON courseid = c.id
LEFT JOIN term t
ON termid = t.id
AND t.startdate < '2011-04-01'
WHERE t.startdate IS NULL
ORDER BY dept,
course;
This will find all course selections that don't have a term.

Related

How Do I return a candidate name even if the vote count is zero

SELECT
candidates.image as image,
candidates.id as cid ,
candidates.name as cname,
choice,
COUNT(choice) as votes
FROM `ballots`
RIGHT JOIN candidates
ON candidates.id = ballots.candidate_id
WHERE ballots.position_id = $position_id
GROUP BY choice
ORDER BY choice DESC
How do I return a candidate name even if the vote count is zero?
You should group by candidate and not by choice.
Also, the condition in the WHERE clause should be moved to the ON clause.
Finally, LEFT joins are easier to read.
Assuming that id is the PRIMARY KEY of candidates you can do this:
SELECT c.image, c.id, c.name AS cname,
COUNT(b.position_id) AS votes
FROM candidates c LEFT JOIN ballots b
ON c.id = b.candidate_id AND b.position_id = $position_id
GROUP BY c.id
ORDER BY c.name;
or maybe you want:
ORDER BY votes DESC;

SQL find highest date in all entries with a date older than x

I try to obtain a list of all customers my company has not had any assignments for in the last year.
SELECT MAX(assignment_date), full_name
FROM assignments
CROSS JOIN customers
WHERE assignments.customer_id = customers.id
AND assignment_date < '2017-01-01' -- Dynamic value from backend
GROUP BY full_name
ORDER BY assignment_date DESC
This does not seem to work as intended however, since it only returns some customers we did have assignments for in that timeframe. How would I go about implementing such a feature?
Try this code:
SELECT MAX(assignment_date), full_name
FROM customers
where id not in (SELECT id FROM customers inner join assigments on customers.id = assignments.customer_id WHERE assignment_date > '2017-01-01' )
This will return all customers in your database and remove all of them who did have assigments in last year. You should get all customers without assigments before '2017-01-01' as a result
left join customers to assignments where assignments.customer_id IS NULL
and assignment_date greater than '2017-01-01' i.e.
SELECT MAX(assignment_date), full_name
FROM assignments
WHERE assignments.customer_id IN
(SELECT customers.id
FROM customers
LEFT JOIN assignments ON assignments.customer_id = customers.id
WHERE assignments.customer_id IS NULL
AND assignment_date > '2017-01-01')
GROUP BY full_name
ORDER BY assignment_date DESC
I would suggest left join, group by and having:
SELECT MAX(assignment_date), full_name
FROM customers c LEFT JOIN
assignments a
ON a.customer_id = c.id
GROUP BY c.full_name
HAVING MAX(a.assignment_date) < '2017-01-01' OR
MAX(a.assignment_date) IS NULL
ORDER BY MAX(assignment_date) DESC;
It seems you want to show all customers with their last assignment date, but you want to restrict that list to customers that had no assignment since 2017-01-01. This means the dates you will be showing will be null for those customers who had never had an assignment and a date before 2017-01-01 for the others.
So outer join the last dates to the customers and only keep the rows where that date is before 2017-01-01 or null:
select c.full_name, a.max_date
from customers c
left join
(
select customer_id, max(assignment_date) as max_date
from assignments
group by customer_id
) a on a.customer_id = c.customer_id
where a.max_date < date '2017-01-01'
or a.max_date is null
order by a.max_date desc;

Sub Query Not IN With Left Join Alternative?

I have Query Like This
SELECT f.ACCOUNT_ID,
f.TGL,
p.ACCOUNT_EMAILADDRESS
FROM distributor_kokola.forecast f
inner join distributor_kokola.push_distributor p on p.ACCOUNT_ID = f.ACCOUNT_ID
where f.ACCOUNT_ID NOT IN(
select ACCOUNT_ID
from distributor_kokola.forecast
where DATE_FORMAT(TGL, "%Y-%m") = DATE_FORMAT(CURDATE(), "%Y-%m")
group by ACCOUNT_ID
)
group by f.ACCOUNT_ID;
That Sub Query work but To Slow so I change it with Left Join, it work faster
SELECT f.ACCOUNT_ID,
f.TGL,
p.ACCOUNT_EMAILADDRESS
FROM distributor_kokola.forecast f
left join(
select ACCOUNT_ID
from distributor_kokola.forecast
where DATE_FORMAT(TGL, "%Y-%m") = DATE_FORMAT(CURDATE(), "%Y-%m")
group by ACCOUNT_ID
)subb on subb.ACCOUNT_ID = f.ACCOUNT_ID
inner join distributor_kokola.push_distributor p on p.ACCOUNT_ID = f.ACCOUNT_ID
group by f.ACCOUNT_ID;
But, My issue is Still Contain wrong Result,
With Not IN, query 1 select where NOT IN query 2.
How can I get like NOT IN query with left join.
Can Anyone Help Me?
thanks.
You have to add a WHERE clause to filter by the results of your LEFT JOIN. If you add an appropriate WHERE clause WHERE subb.ACCOUNT_ID IS NULL, it should work as expected (since you used a GROUP BY in your subquery, there's no danger of duplicate rows):
SELECT f.ACCOUNT_ID,
f.TGL,
p.ACCOUNT_EMAILADDRESS
FROM distributor_kokola.forecast f
left join(
select ACCOUNT_ID
from distributor_kokola.forecast
where DATE_FORMAT(TGL, "%Y-%m") = DATE_FORMAT(CURDATE(), "%Y-%m")
group by ACCOUNT_ID
) subb on subb.ACCOUNT_ID = f.ACCOUNT_ID
inner join distributor_kokola.push_distributor p on p.ACCOUNT_ID = f.ACCOUNT_ID
WHERE sub.ACCOUNT_ID IS NULL
group by f.ACCOUNT_ID;
Update
The goal of our LEFT JOIN is to find all rows in our forecast table that don't have a matching row in the subquery. Therefore, we need a WHERE clause that removes all rows with a matching row - WHERE sub.ACCOUNT_ID IS NULL fits quite nicely.
SO user #quassnoi has written a wonderful comparison of different methods to achieve this goal.

MySql order by clause not working

In mysql query I use order by, but it is not working.
When I do this
SELECT t.id,t.user_id,t.title,c.comment,d.has_answer,IF(c.id IS NULL, t.date_created, d.recent_date) recent_date,MIN(i.id) image_id
FROM threads t
LEFT JOIN comments c ON c.thread_id = t.id
INNER JOIN (
SELECT thread_id, MAX(date_sent) recent_date, MAX(is_answer) has_answer
FROM comments
GROUP BY thread_id
) d ON c.id IS NULL OR (d.thread_id = c.thread_id AND d.recent_date = c.date_sent)
LEFT JOIN thread_images i ON t.id = i.thread_id
WHERE t.user_id = t.user_id
GROUP BY t.id
ORDER BY d.recent_date DESC
LIMIT 0, 10
It doesn't properly order them. But if I do this:
SELECT *
FROM (
SELECT t.id,t.user_id,t.title,c.comment,d.has_answer,IF(c.id IS NULL, t.date_created, d.recent_date) recent_date,MIN(i.id) image_id
FROM threads t
LEFT JOIN comments c ON c.thread_id = t.id
INNER JOIN (
SELECT thread_id, MAX(date_sent) recent_date, MAX(is_answer) has_answer
FROM comments
GROUP BY thread_id
) d ON c.id IS NULL OR (d.thread_id = c.thread_id AND d.recent_date = c.date_sent)
LEFT JOIN thread_images i ON t.id = i.thread_id
WHERE t.user_id = t.user_id
GROUP BY t.id
LIMIT 0, 10) qwerty
ORDER BY recent_date DESC
Then it does work. Why does the top one not work, and is the second way the best way to fix that?
Thanks
Those two statements are ordering by two different things.
The second statement is ordering by the result of an expression in the SELECT list.
But the first statement specifies ordering by a value of recent_date returned by the inline view d; if you remove "d." from in front of recent_date, then the ORDER BY clause would reference the alias assigned to the expression in the SELECT list, as the second statement does.
Because recent_date is an alias for an expression the SELECT list, these two are equivalent:
ORDER BY recent_date
ORDER BY IF(c.id IS NULL, t.date_created, d.recent_date)
^^
but those are significantly different from:
ORDER BY d.recent_date
^^
Note that the non-standard use of the GROUP BY clause may be masking some values of recent_date which are discarded by the query. This usage of the GROUP BY clause is a MySQL extension to the SQL Standard; most other relational databases would throw an error with this statement. It's possible to get MySQL to throw the same type of error by enabling the ONLY_FULL_GROUP_BY SQL mode.
Q Is the second statement the best way to fix that?
A If that statement guarantees that the resultset returned meets your specification, then it's a workable approach. (One downside is the overhead of the inline view query.)
But I strongly suspect that the second statement is really just masking the problem, not really fixing it.
SELECT t.id,t.user_id,t.title,c.comment,d.has_answer,IF(c.id IS NULL, t.date_created, d.recent_date) recent_date,MIN(i.id) image_id
FROM (threads t
LEFT JOIN comments c ON c.thread_id = t.id
INNER JOIN (
SELECT thread_id, MAX(date_sent) recent_date, MAX(is_answer) has_answer
FROM comments
GROUP BY thread_id
) d ON c.id IS NULL OR (d.thread_id = c.thread_id AND d.recent_date = c.date_sent)
LEFT JOIN thread_images i ON t.id = i.thread_id
WHERE t.user_id = t.user_id
GROUP BY t.id
LIMIT 0, 10) x
ORDER BY d.recent_date DESC

MySQL Query not displaying correctly

I am having to set up a query that retrieves the last comment made on a customer, if no one has commented on them for more than 4 weeks. I can make it work using the query below, but for some reason the comment column won't display the latest record. Instead it displays the oldest, however the date shows the newest. It may just be because I'm a noob at SQL, but what exactly am I doing wrong here?
SELECT DISTINCT
customerid, id, customername, user, MAX(date) AS 'maxdate', comment
FROM comments
WHERE customerid IN
(SELECT DISTINCT id FROM customers WHERE pastdue='1' AND hubarea='1')
AND customerid NOT IN
(SELECT DISTINCT customerid FROM comments WHERE DATEDIFF(NOW(), date) <= 27)
GROUP BY customerid
ORDER BY maxdate
The first "WHERE" clause is just ensuring that it shows only customers from a specific area, and that they are "past due enabled". The second makes sure that the customer has not been commented on within the last 27 days. It's grouped by customerid, because that is the number that is associated with each individual customer. When I get the results, everything is right except for the comment column...any ideas?
Join much better to nested query so you use the join instead of nested query
Join increase your speed
this query resolve your problem.
SELECT DISTINCT
customerid,id, customername, user, MAX(date) AS 'maxdate', comment
FROM comments inner join customers on comments.customerid = customers.id
WHERE comments.pastdue='1' AND comments.hubarea='1' AND DATEDIFF(NOW(), comments.date) <= 27
GROUP BY customerid
ORDER BY maxdate
I think this might probably do what you are trying to achieve. If you can execute it and maybe report back if it does or not, i can probably tweak it if needed. Logically, it ' should' work - IF i have understood ur problem correctly :)
SELECT X.customerid, X.maxdate, co.id, c.customername, co.user, co.comment
FROM
(SELECT customerid, MAX(date) AS 'maxdate'
FROM comments cm
INNER JOIN customers cu ON cu.id = cm.customerid
WHERE cu.pastdue='1'
AND cu.hubarea='1'
AND DATEDIFF(NOW(), cm.date) <= 27)
GROUP BY customerid) X
INNER JOIN comments co ON X.customerid = co.customerid and X.maxdate = co.date
INNER JOIN customer c ON X.customerid = c.id
ORDER BY X.maxdate
You need to have subquery for each case.
SELECT a.*
FROM comments a
INNER JOIN
(
SELECT customerID, max(`date`) maxDate
FROM comments
GROUP BY customerID
) b ON a.customerID = b.customerID AND
a.`date` = b.maxDate
INNER JOIN
(
SELECT DISTINCT ID
FROM customers
WHERE pastdue = 1 AND hubarea = 1
) c ON c.ID = a.customerID
LEFT JOIN
(
SELECT DISTINCT customerid
FROM comments
WHERE DATEDIFF(NOW(), date) <= 27
) d ON a.customerID = d.customerID
WHERE d.customerID IS NULL
The first join gets the latest record for each customer.
The second join shows only customers from a specific area, and that they are "past due enabled".
The third join, which uses LEFT JOIN, select all customers that has not been commented on within the last 27 days. In this case,only records without on the list are selected because of the condition d.customerID IS NULL.
But tomake your query shorter, if the customers table has already unique records for customer, then you don't need to have subquery on it.Directly join the table and put the condition on the WHERE clause.
SELECT a.*
FROM comments a
INNER JOIN
(
SELECT customerID, max(`date`) maxDate
FROM comments
GROUP BY customerID
) b ON a.customerID = b.customerID AND
a.`date` = b.maxDate
INNER JOIN customers c
ON c.ID = a.customerID
LEFT JOIN
(
SELECT DISTINCT customerid
FROM comments
WHERE DATEDIFF(NOW(), date) <= 27
) d ON a.customerID = d.customerID
WHERE d.customerID IS NULL AND
c.pastdue = 1 AND
c.hubarea = 1
Two of your table columns are not contained in either an aggregate function or the GROUP BY clause. for example suppose that you have two data rows with the same customer id and same date, but with different comment data. how SQL should aggregate these two rows? :( it will generate an error...
try this
select customerid, id, customername, user,date, comment from(
select customerid, id, customername, user,date, comment,
#rank := IF(#current_customer = id, #rank+ 1, 1),
#current_customer := id
from comments
where customerid IN
(SELECT DISTINCT id FROM customers WHERE pastdue='1' AND hubarea='1')
AND customerid NOT IN
(SELECT DISTINCT customerid FROM comments WHERE DATEDIFF(NOW(), date) <= 27)
order by customerid, maxdate desc
) where rank <= 1