Two Select statements into one - mysql

I'm using MySql 8.0.23 and have two select statements. The first one reads like this:
SELECT w.userid,w.reportdate, t.teamname, sum(w.worked)/60 as Worked FROM apticproject.view_workedtime as w
inner join user u on u.userid=w.userid
left outer join teammembers m on m.member=w.userid
left outer join teams t on t.teamid=m.team
where reportdate >= '2021-03-01' and reportdate <'2021-04-01'
group by w.userid
order by fullname ;
And gives the following output:
The second select statement reads like this:
SELECT r.userid, sum(r.invoicetime)/60 as invoicetime FROM apticproject.view_registeredtime as r
inner join user u on u.userid=r.userid
left join teammembers m on m.member=r.userid
left join teams t on t.teamid=m.team
where fromdate >= '2021-03-01' and fromdate <'2021-04-01' and r.invoiced=1 and r.approved=1 and charge_customer=1 and r.zeroinvoice=0
group by userid
order by fullname;
And gives the following output:
I want to be able to join the invoicetime column from the second select statement to the first select statement so that the invoicetime column is shown after the Worked column in the first select statement. As you can see I have the userid which can be used as a connection point. What is the most efficient way to do this? Your help is much appreciated.

I managed to find a solution as shown below. In MySQL you don't have a FULL JOIN, only Union exists, and this is the syntax I have used:
select x.userid, x.username, x.fullname,x.reportdate, x.teamname, x.Worked,y.invoicetime
from
(SELECT w.userid, u.username, u.fullname,w.reportdate, t.teamname, sum(w.worked)/60 as Worked FROM apticproject.view_workedtime as w
inner join user u on u.userid=w.userid
left outer join teammembers m on m.member=w.userid
left outer join teams t on t.teamid=m.team
where reportdate >= '2021-03-01' and reportdate <'2021-04-01'
group by w.userid) as x
left join
(SELECT r.userid, sum(r.invoicetime)/60 as invoicetime FROM apticproject.view_registeredtime as r
inner join user u on u.userid=r.userid
left join teammembers m on m.member=r.userid
left join teams t on t.teamid=m.team
where fromdate >= '2021-03-01' and fromdate <'2021-04-01' and r.invoiced=1 and r.approved=1 and charge_customer=1 and r.zeroinvoice=0
group by userid) as y on y.userid=x.userid
Union
select x.userid, x.username, x.fullname,x.reportdate, x.teamname, x.Worked,y.invoicetime
from
(SELECT w.userid, u.username, u.fullname,w.reportdate, t.teamname, sum(w.worked)/60 as Worked FROM apticproject.view_workedtime as w
inner join user u on u.userid=w.userid
left outer join teammembers m on m.member=w.userid
left outer join teams t on t.teamid=m.team
where reportdate >= '2021-03-01' and reportdate <'2021-04-01'
group by w.userid) as x
right join
(SELECT r.userid, sum(r.invoicetime)/60 as invoicetime FROM apticproject.view_registeredtime as r
inner join user u on u.userid=r.userid
left join teammembers m on m.member=r.userid
left join teams t on t.teamid=m.team
where fromdate >= '2021-03-01' and fromdate <'2021-04-01' and r.invoiced=1 and r.approved=1 and charge_customer=1 and r.zeroinvoice=0
group by userid) as y on y.userid=x.userid
order by fullname;

If you don't care to see items from your second query that have no user records in the first, you can drop the union and the whole right join in the second half of Darko86's answer.

Related

Select the first record of another table inside a select - MYSQL

I´m trying to make a query listing all clients, and also get the last comment and
the date of that comment inside the table of history_client inside a single query for it to be listed.
select a.id_client,a.name,a.lastname,(select b.date_created,b.comentary
from history_of_client b where a.id_client = b.id_client_asociate) from clients_main_table
You could use an inner join on max(date_created) for id_client on history table and join
SELECT a.id_client,a.name,a.lastname, h.commentary
FROM clients_main_table a
INNER join (
select b.id_client_asociate, max(b.date_created) max_date
from history_of_client
group by b.id_client_asociate ) t on t.id_client_asociate = a.id_client
INNER JOIN history_of_client h on h.id_client_asociate = t.id_client_asociate
and h.date_created = t.max_date
Use the LEFT JOIN and INNER join to get your desired result set.
select a.id_client,
a.name,
a.lastname,
hc.date_created,
hc.comentary
from clients_main_table c
left join (select id_client_asociate,max(date_created) dt from history_of_client group by id_client_asociate) h
on (c.id_client = b.id_client_asociate)
inner join history_of_client hc
on (hc.id_client_asociate = b.id_client_asociate and hc.date_created = h.date_created)

Join of three different mysql queries tables

I want to join three different queries.
Here are my queries
Query1:
SELECT u.user_name,u.first_name
FROM users u join users_cstm uc on u.id=uc.id_c
WHERE u.deleted=0?
Query2:
SELECT l.assigned_user_id,count(*) AS lead_count
FROM lead l GROUP BY l.assigned_user_id?
Query3:
SELECT l.assigned_user_id,AVG(DATEDIFF(l.date_modified,l.date_entered)) AS avgdays
FROM leads l GROUP BY l.assigned_user_id?
and so on.
This is the result I am looking for user_name, first_name,lead_count,avgdays. from three tables.
BigQuery join of three tables
I have tried my solution from the above link. But I didn't get the result.
Try below query:-
SELECT u.user_name,u.first_name,
lead_table.lead_count,lead_table.avgdays
FROM users u join users_cstm uc on u.id=uc.id_c
left join
(SELECT l.assigned_user_id,
AVG(l.date_modified) AS avgdays,
count(*) AS lead_count
FROM leads l GROUP BY l.assigned_user_id) lead_table
on u.id=lead_table.assigned_user_id
WHERE u.deleted=0;
Try this:
SELECT id,user_name,first_name,lead_count,avgdays from
(SELECT id,user_name,first_name,lead_count from
(SELECT u.id,u.user_name,u.first_name FROM users u,users_cstm uc where u.id=uc.id_c and u.deleted=0) as a
LEFT JOIN
(SELECT l.assigned_user_id,count(*) AS lead_count FROM lead l GROUP BY l.assigned_user_id) as b
on a.id = b.assigned_user_id) as a
LEFT JOIN
(SELECT l.assigned_user_id,AVG(DATEDIFF(l.date_modified,l.date_entered)) AS avgdays
FROM leads l GROUP BY l.assigned_user_id) as b
on a.id = b.assigned_user_id

Mysql select with IF function sub query

I am trying to get a query to work with php. Basically it should first check that a specific booking has not been made then query database for all available vehicles and drivers.
This is the query so far:
IF EXISTS(SELECT * FROM bookings LEFT JOIN status WHERE bookings.status_id = '.$booking.')
BEGIN
select *
FROM bookings as b
LEFT JOIN drivers as d where b.driver_id !="d.driver_id"
LEFT JOIN vehicles as v where b.vehicle_id !="v.vehicle_id"
LEFT JOIN status as s where b.status_id !="'.$booking.'"
ORDER BY b.bookingDate DESC
END
Join bookings:
SELECT *
FROM bookings as b
LEFT JOIN drivers as d where b.driver_id !="d.driver_id"
LEFT JOIN vehicles as v where b.vehicle_id !="v.vehicle_id"
LEFT JOIN status as s where b.status_id !="'.$booking.'"
CROSS JOIN (
SELECT 1
FROM bookings
WHERE bookings.status_id = '.$booking.'
LIMIT 1
) t
ORDER BY b.bookingDate DESC

MySQL - query ordered by date failing to get the latest record

I've got a database set up as follows:
http://sqlfiddle.com/#!9/2c5fc
What I'm looking to do is get a list of each store, and their last budget amount (Each schedule's total in the budget * their apportionment for that schedule / 100).
Some stores might not have apportionments set for the last budget, so I need the last budget where they have an apportionment set, or NULL if no apportionment has been set or no budget exists.
I've got the following SQL query:
SELECT s.StoreID,s.CentreID, budgetcalc.amount, budgetcalc.BudgetDate FROM store as s
LEFT JOIN centre on s.CentreID = centre.CentreID
LEFT JOIN (SELECT BudgetDate, SUM(sch.Amount*appt.Percentage/100) as amount, appt.StoreID from budget b
INNER JOIN schedule as sch on b.BudgetID = sch.BudgetID
INNER JOIN apportionment as appt on sch.ScheduleID = appt.ScheduleID
GROUP BY appt.StoreID, b.BudgetID
ORDER BY STR_TO_DATE(b.BudgetDate,'%d-%m-%y') DESC
) as budgetcalc on s.StoreID = budgetcalc.StoreID
GROUP BY s.StoreID
ORDER BY s.StoreID, STR_TO_DATE(budgetcalc.BudgetDate,'%d-%m-%y') DESC;
However this has the issue of not returning the last year, it will return a previous year seemingly at random regardless of the order in which I return the subquery.
It is difficult to work out from just the table declarations, but you need to get the latest budget date for each store, then join that against your sub query that gets the budget details for each store / budget.
Untested but something like this:-
SELECT s.StoreID,
s.CentreID,
budgetcalc.amount,
budgetcalc.BudgetDate
FROM store as s
LEFT OUTER JOIN centre ON s.CentreID = centre.CentreID
LEFT OUTER JOIN
(
SELECT appt.StoreID,
MAX(BudgetDate) AS latestBudgetDate
FROM budget b
INNER JOIN schedule as sch ON b.BudgetID = sch.BudgetID
INNER JOIN apportionment as appt ON sch.ScheduleID = appt.ScheduleID
GROUP BY appt.StoreID
) latest_budget
ON s.StoreID = latest_budget.StoreID
LEFT OUTER JOIN
(
SELECT BudgetDate,
appt.StoreID,
SUM(sch.Amount*appt.Percentage/100) as amount
FROM budget b
INNER JOIN schedule as sch ON b.BudgetID = sch.BudgetID
INNER JOIN apportionment as appt ON sch.ScheduleID = appt.ScheduleID
GROUP BY appt.StoreID, b.BudgetID
) as budgetcalc
ON latest_budget.StoreID = budgetcalc.StoreID
AND latest_budget.latestBudgetDate = budgetcalc.BudgetDate
ORDER BY s.StoreID,
budgetcalc.BudgetDate DESC;
With help from Kickstart, this is the answer that works:
SELECT s.StoreID,s.CentreID, SUM(sch.Amount*appt.Percentage/100) as amount, b.BudgetDate FROM store as s
INNER JOIN centre on s.CentreID = centre.CentreID
LEFT JOIN budget as b on b.BudgetID =
(
SELECT budget.BudgetID from budget
INNER JOIN schedule on budget.BudgetID = schedule.BudgetID
INNER JOIN apportionment on schedule.ScheduleID = apportionment.ScheduleID
where CentreID = s.CentreID AND apportionment.StoreID = s.StoreID
ORDER BY BudgetDate DESC limit 1
)
LEFT JOIN schedule as sch on b.BudgetID = sch.BudgetID
LEFT JOIN apportionment as appt on sch.ScheduleID = appt.ScheduleID AND appt.StoreID = s.StoreID
GROUP BY s.StoreID
ORDER BY s.StoreID ASC;

mySQL Sub Select needed

I have three tables, libraryitems, copies and loans.
A libraryitem hasMany copies, and a copy hasMany loans.
I'm trying to get the latest loan entry for a copy only; The query below returns all loans for a given copy.
SELECT
libraryitems.title,
copies.id,
copies.qruuid,
loans.id AS loanid,
loans.status,
loans.byname,
loans.byemail,
loans.createdAt
FROM copies
INNER JOIN libraryitems ON copies.libraryitemid = libraryitems.id AND libraryitems.deletedAt IS NULL
LEFT OUTER JOIN loans ON copies.id = loans.copyid
WHERE copies.libraryitemid = 1
ORDER BY copies.id ASC, loans.createdAt DESC
I know there needs to be a sub select of some description in here, but struggling to get the correct syntax. How do I only return the latest, i.e MAX(loans.createdAt) row for each distinct copy? Just using group by copies.id returns the earliest, rather than latest entry.
Image example below:
in the subquery , getting maximum created time for a loan i.e. latest entry and joining back with loans to get other details.
SELECT
T.title,
T.id,
T.qruuid,
loans.id AS loanid,
loans.status,
loans.byname,
loans.byemail,
loans.createdAt
FROM
(
SELECT C.id, C.qruuid, L.title, MAX(LN.createdAt) as maxCreatedTime
FROM Copies C
INNER JOIN libraryitems L ON C.libraryitemid = L.id
AND L.deletedAt IS NULL
LEFT OUTER JOIN loans LN ON C.id = LN.copyid
GROUP BY C.id, C.qruuid, L.title) T
JOIN loans ON T.id = loans.copyid
AND T.maxCreatedTime = loans.createdAt
A self left join on loans table will give you latest loan of a copy, you may join the query to the other tables to fetch the desired output.
select * from loans A
left outer join loans B
on A.copyid = B.copyid and A.createdAt < B.createdAt
where B.createdAt is null;
This is your query with one simple modification -- table aliases to make it clearer.
SELECT li.title, c.id, c.qruuid,
l.id AS loanid, l.status, l.byname, l.byemail, l.createdAt
FROM copies c INNER JOIN
libraryitems li
ON c.libraryitemid = li.id AND
li.deletedAt IS NULL LEFT JOIN
loans l
ON c.id = l.copyid
WHERE c.libraryitemid = 1
ORDER BY c.id ASC, l.createdAt DESC ;
With this as a beginning let's think about what you need. You want the load with the latest createdAt date for each c.id. You can get this information with a subquery:
select l.copyid, max(createdAt)
from loans
group by l.copyId
Now, you just need to join this information back in:
SELECT li.title, c.id, c.qruuid,
l.id AS loanid, l.status, l.byname, l.byemail, l.createdAt
FROM copies c INNER JOIN
libraryitems li
ON c.libraryitemid = li.id AND
li.deletedAt IS NULL LEFT JOIN
loans l
ON c.id = l.copyid LEFT JOIN
(SELECT l.copyid, max(l.createdAt) as maxca
FROM loans
GROUP BY l.copyid
) lmax
ON l.copyId = lmax.copyId and l.createdAt = lmax.maxca
WHERE c.libraryitemid = 1
ORDER BY c.id ASC, l.createdAt DESC ;
This should give you the most recent record. And, the use of left join should keep all copies, even those that have never been leant.