MySQL INNER JOIN Select only one row from other table - mysql

I have been trying to figure out a MySQL statement to perform the following.
I have a table with that stores jobs (tbl_jobs).
Another table that stores work scheduling (tbl_schedule) in the form of fixed time slots.
I want the resulting query to show all jobs scheduled today, check if the jobs are already scheduled (timeslot field) and return the earliest time slot.
My timeslots are stored as numbers from 1-8 so I used MIN to get the smallest number.
There can be the same job spanning multiple timeslots.
I tried a code from MySQL INNER JOIN select only one row from second table but I believe I don't understand the query in depth enough to make my own statement for my purposes
SELECT a.*, c.*
FROM tbl_jobs a
INNER JOIN tbl_schedule c
ON a.job_id = c.job_id
INNER JOIN (
SELECT job_id, MIN(timeslot) ts
FROM tbl_schedule
GROUP BY job_id
) b ON c.job_id = b.job_id
WHERE date = '2018-01-05'
This query on returns jobs that are scheduled and the ones that are not scheduled do not show up at all.
Would appreciate if anyone can assist me in where I should go from here? I am at a roadblock so, I decided to post here for help! Thanks in advance!

To get unscheduled job, use the left join
SELECT a.*, c.*
FROM tbl_jobs a
LEFT JOIN tbl_schedule c
ON a.job_id = c.job_id
LEFT JOIN (
SELECT job_id, MIN(timeslot) ts
FROM tbl_schedule
GROUP BY job_id AND
) b ON c.job_id = b.job_id
WHERE date = '2018-01-05'

Related

SQL Query for getting maximum value from a column Joining from Another Table

This is a slight variant of the question I asked here
SQL Query for getting maximum value from a column
I have a Person Table and an Activity Table with the following data
-- PERSON-----
------ACTIVITY------------
I have got this data in the database about users spending time on a particular activity.
I intend to get the data when every user has spent the maximum number of hours.
My Query is
Select p.Id as 'PersonId',
p.Name as 'Name',
act.HoursSpent as 'Hours Spent',
act.Date as 'Date'
From Person p
Left JOIN (Select MAX(HoursSpent), Date from Activity
Group By HoursSpent, Date) act
on act.personId = p.Id
but it is giving me all the rows for Person and not with the Maximum Numbers of Hours Spent.
This should be my result.
You have several issues with your query:
The subquery to get hours is aggregated by date, not person.
You don't have a way to bring in other columns from activity.
You can take this approach -- joins and group by, but it requires two joins:
select p.*, a.* -- the columns you want
from Person p left join
activity a
on a.personId = p.id left join
(select personid, max(HoursSpent) as max_hoursspent
from activity a
group by personid
) ma
on ma.personId = a.personId and
ma.max_hoursspent = a.hoursspent;
Note that this can return duplicates for a given person -- if there are ties for the maximum.
This is written more colloquially using row_number():
select p.*, a.* -- the columns you want
from Person p left join
(select a.*,
row_number() over (partition by a.personid order by a.hoursspent desc) as seqnum
from activity a
) a
on a.personId = p.id and a.seqnum = 1
ma.max_hoursspent = a.hoursspent;

Mysql Query where max(time) less than today

I have two tables, the first table ( job ) stores the data and the second table ( job_locations ) stores the locations for each job, I'm trying to show the number of jobs that job locations are less than today
I use the DateTime for the Date Column
unfortunately, the numbers that appear after test the next code are wrong
My code
SELECT *
FROM `job`
left join job_location
on job_location.job_id = job.id
where job_location.cutoff_time < CURDATE()
group by job.id
Please help me to write the working Query.
I think you need to rephrase your query slightly. Select a count of jobs where the cutoff time is earlier than the start of today.
SELECT
j.id,
COUNT(CASE WHEN jl.cutoff_time < CURDATE() THEN 1 END) AS cnt
FROM job j
LEFT JOIN job_location jl;
ON j.id = jl.job_id
GROUP BY
j.id;
Note that the left join is important here because it means that we won't drop any jobs having no matching criteria. Instead, those jobs would still appear in the result set, just with a zero count.
As a note, you can simplify the count (in MySQL). And, assuming that all jobs have at least one location, you don't need a JOIN at all. So:
SELECT jl.job_id, sum( jl.cutoff_time < CURDATE() )
FROM job_location jl
GROUP BY jl.job_id;
If this is not correct (and you need the JOIN), then the condition on the date should go in the ON clause:
SELECT jl.job_id, COUNT(jo.job_id)
FROM job LEFT JOIN
job_location jl
ON jl.job_id = j.id AND jl.cutoff_time < CURDATE()
GROUP BY jl.job_id;

mysql leftjoin by max autoincrement id?

A) users
B) subscribtion
C) package information
I've table where B is a link between A and C , the query selected from A where B has row id for A and join C by B id .
Full example :
SELECT a.*,c.packageTitle
FROM users AS a
LEFT JOIN subscribe AS b ON (b.userid = a.userid)
LEFT JOIN package AS c ON (b.packageid = c.packageid)
my problem if user has multi subscription in C, i cannot get latest subscription row in loop query, i also used MAX(c.packageid) inside SELECT failed also .
Goal : get latest record in B assigned by A id .
any advice is very much appreciated
I don't think you were far off by trying to use MAX() to obtain the record with the latest package ID (which assumes that this ID is an increasing auto-increment column). In my answer below, the subquery identifies the latest package ID for each user record, using a GROUP BY. This subquery is then used to filter the correct records from your original query.
SELECT a.userid, b.*
FROM users AS a
LEFT JOIN subscribe AS b
ON b.userid = a.userid
LEFT JOIN package AS c
ON b.packageid = c.packageid
INNER JOIN
(
SELECT a.userid, MAX(c.packageTitle) AS maxPackageTitle
FROM users AS a
LEFT JOIN subscribe AS b
ON b.userid = a.userid
LEFT JOIN package AS c
ON b.packageid = c.packageid
GROUP BY a.userid
) t
ON a.userid = t.userid AND c.packageTitle = t.maxPackageTitle
As a note, this query would greatly benefit from something called a Common Table Expression (CTE), which is available in other RBDMS such as SQL Server and Oracle. A CTE would make the query much less repetitive and more readable.
This should be simple enough. In Mysql you just as you said put a max on the select along with a group by. So it would look something like:
SELECT username, id_info, ...
FROM
(
SELECT a.username, a.id_info, c.packageTitle, MAX(package_id)
FROM users AS a
LEFT JOIN subscribe AS b
ON b.userid = a.userid
LEFT JOIN package AS c
ON b.packageid = c.packageid
GROUP BY a.username, a.id_info, c.packageTitle
)
Remember to list all columns in the select which are also being grouped, except the one on which you are taking the max, or the query will fail.

SQL Query, subquery minus subquery?

Ok, so Ive been trying to get this query working for hours now, but nothing I seem to do will get me the results I am after.
SELECT COALESCE(SUM(ps.cost), 0) AS ps_total
FROM Customers c
LEFT JOIN ProductSales ps ON c.customer_ID = ps.customer_ID
GROUP BY c.sex;
SELECT COALESCE(SUM(hc.cost), 0) AS hc_total
FROM Customers c
LEFT JOIN HairCuts hc ON c.customer_ID = hc.customer_ID
GROUP BY c.sex;
So the above two queries work fine. Each one finds the total spent on either products or hair cuts and groups by gener thus giving me the total spent on cuts and products for males and females individually.However somehow I need to combine these in such a way that I can display the gender(s) that spent more on products than on haircuts.
Any help with this would be very much appreciated.
P.S hopefully the question is clear enough. If not Ill try to elaborate.
Another way you can join your both query results as
SELECT t1.sex,
COALESCE(t1.ps_total - t2.hc_total,0) AS `difference`
FROM
(SELECT COALESCE(SUM(ps.cost), 0) AS ps_total ,c.sex
FROM Customers c
LEFT JOIN ProductSales ps ON c.customer_ID = ps.customer_ID
GROUP BY c.sex) t1
LEFT JOIN
(SELECT COALESCE(SUM(hc.cost), 0) AS hc_total ,c.sex
FROM Customers c
LEFT JOIN HairCuts hc ON c.customer_ID = hc.customer_ID
GROUP BY c.sex) t2
USING(sex)
HAVING difference > 0
Edit from comments
I have used a short syntax for ON() clause like USING(sex) = ON(t1.sex=t2.sex) if you have a same name for a column in both tables you can use USING() if you have different then you need to use ON() syntax
Like
Table1 column(category_id primary key,...)
Table2 column(category_id foreign key,...)
Then you can easily use USING()
SELECT * FROM
Table1
JOIN Table2
USING(category_id )
But if you have different name for association then you need to use ON() clause

mysql subquery inside a LEFT JOIN

I have a query that needs the most recent record from a secondary table called tbl_emails_sent.
That table holds all the emails sent to clients. And most clients have several to hundreds of emails recorded. I want to pull a query that displays the most recent.
Example:
SELECT c.name, c.email, e.datesent
FROM `tbl_customers` c
LEFT JOIN `tbl_emails_sent` e ON c.customerid = e.customerid
I'm guessing a LEFT JOIN with a subquery would be used, but I don't delve into subqueries much. Am I going the right direction?
Currently the query above isn't optimized for specifying the most recent record in the table, so I need a little assistance.
It should be like this, you need to have a separate query to get the maximum date (or the latest date) that the email was sent.
SELECT a.*, b.*
FROM tbl_customers a
INNER JOIN tbl_emails_sent b
ON a.customerid = b.customerid
INNER JOIN
(
SELECT customerid, MAX(datesent) maxSent
FROM tbl_emails_sent
GROUP BY customerid
) c ON c.customerid = b.customerid AND
c.maxSent = b.datesent
Would this not work?
SELECT t1.datesent,t1.customerid,t2.email,t2.name
FROM
(SELECT max(datesent) AS datesent,customerid
FROM `tbl_emails_sent`
) as t1
INNER JOIN `tbl_customers` as t2
ON t1.customerid=t2.customerid
Only issue you have then is what if two datesents are the same, what is the deciding factor in which one gets picked?