Exclude joined columns from a mysql query - mysql

I have the following query:
SELECT sa.*, d.day, TIME_FORMAT(timefrom.time, '%H:%i') AS time_from, TIME_FORMAT(timeto.time, '%H:%i') AS time_to
FROM staff s
INNER JOIN staff_availability sa
ON sa.staff_id = s.staff_id
INNER JOIN days d
ON d.day_id = sa.day_id
LEFT JOIN time_slots AS timefrom
ON timefrom.time_slot_id = sa.time_from
LEFT JOIN time_slots AS timeto
ON timeto.time_slot_id = sa.time_to
INNER JOIN users u
ON s.user_id = u.user_id
WHERE u.user_id = :user_id
I am using the alias time_from and time_to as the formatted times picked out of the time_slots table which are joined on with the staff_availability table.
The query is returning the following:
staff_availability_id staff_id day_id time_from(join) time_to(join) day time_from (alias) time_to (alias)
Is there any way I can exclude the join columns from the results?

you have to select them manually.
change this
SELECT sa.*
to
SELECT sa.staff_availability_id , sa.staff_id,....--what ever you want to select and dont select those you mentioned

select the columns as,
SELECT sa.staff_availability_id ,sa.staff_id,d.day, TIME_FORMAT(timefrom.time, '%H:%i') AS time_from, TIME_FORMAT(timeto.time, '%H:%i') AS time_to
FROM staff s
INNER JOIN staff_availability sa
ON sa.staff_id = s.staff_id
INNER JOIN days d
ON d.day_id = sa.day_id
LEFT JOIN time_slots AS timefrom
ON timefrom.time_slot_id = sa.time_from
LEFT JOIN time_slots AS timeto
ON timeto.time_slot_id = sa.time_to
INNER JOIN users u
ON s.user_id = u.user_id
WHERE u.user_id = :user_id

Related

Two Select statements into one

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.

Get name, date and sum from orders in March

I have this query:
SELECT *
FROM ((orders_books
JOIN books ON orders_books.id_book = books.id)
JOIN orders ON orders_books.id_order=orders.id)
JOIN users ON user_id=users.id
WHERE date >='2019-03-1' AND date <= '2019-03-31';
Query result: https://image.prntscr.com/image/s3ngzzYrSd27mFib9HbLmA.png
I find number of orders:
SELECT name, date, SUM(book_price)
FROM ((orders_books
INNER JOIN books ON orders_books.id_book = books.id)
INNER JOIN orders ON orders_books.id_order=orders.id)
INNER JOIN users ON user_id=users.id
WHERE date >='2019-03-1' AND date <= '2019-03-31';
[Amount for all orders] : https://image.prntscr.com/image/o88Hf4uKSHGuZ2ESUECzuA.png
But I need to find the order amount separately for each order.
How about:
SELECT id_order, SUM(book_price)
FROM ((orders_books
INNER JOIN books ON orders_books.id_book = books.id)
INNER JOIN orders ON orders_books.id_order=orders.id)
INNER JOIN users ON user_id=users.id
WHERE date >='2019-03-1' AND date <= '2019-03-31'
GROUP BY id_order;
SELECT orders.id, SUM(book_price)
FROM ((orders_books
INNER JOIN books ON orders_books.id_book = books.id)
INNER JOIN orders ON orders_books.id_order=orders.id)
INNER JOIN users ON user_id=users.id
WHERE date >='2019-03-1' AND date <= '2019-03-31'
GROUP BY order_id;
If you need the sum for order.id then use group by orders.id
SELECT orders.id SUM(book_price)
FROM orders_books
INNER JOIN books ON orders_books.id_book = books.id
INNER JOIN orders ON orders_books.id_order=orders.id
WHERE date >='2019-03-1' AND date <= '2019-03-31'
group by orders.id

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;

sql select distinc where max date

I have 3 tables "maintenances", "cars", "users" . I want to select all data from table maintenance with a distinct car_id and the last record for each distinct (based on max maintenance_date)
SELECT
m. * , u.username, c.Model, c.Make, c.License, c.Milage, COUNT( m.process_id ) AS count_nr
FROM
maintenances AS m
LEFT JOIN users AS u ON u.id = m.user_id
LEFT JOIN cars AS c ON c.id = m.car_id
WHERE
maintenance_date = (SELECT MAX(maintenance_date) FROM maintenances WHERE car_id = m.car_id)
The problem is that this query returns only one record which has the max date from all records. I want all records (distinct car_id and from records with the same car_id to display only values for max(maintenance_date))
This is your query:
SELECT m. * , u.username, c.Model, c.Make, c.License, c.Milage, COUNT( m.process_id ) AS count_nr
----------------------------------------------------------------^
FROM maintenances AS m LEFT JOIN
users AS u
ON u.id = m.user_id LEFT JOIN
cars AS c
ON c.id = m.car_id
WHERE maintenance_date = (SELECT MAX(maintenance_date) FROM maintenances WHERE car_id = m.car_id);
It is an aggregation query. Without a group by, only one row is returned (all the rows are in one group). So, add the group by:
SELECT m. * , u.username, c.Model, c.Make, c.License, c.Milage, COUNT( m.process_id ) AS count_nr
FROM maintenances AS m LEFT JOIN
users AS u
ON u.id = m.user_id LEFT JOIN
cars AS c
ON c.id = m.car_id
WHERE maintenance_date = (SELECT MAX(m2.maintenance_date) FROM maintenances m2 WHERE m2.car_id = m.car_id);
GROUP BY c.id
I also fixed the correlation statement, to be clear that it is correlated to the outer query.
add GROUP BY u.username .
WHERE
maintenance_date = (SELECT MAX(maintenance_date) FROM maintenances WHERE car_id = m.car_id)
GROUP BY u.username

select certain date till now mysql

I need my query to select unix timestamps which range from a particular past date till now?For example I need to select '2013-01-01' till current date. I was able to do it for a particular year. Any help would be appreciated.
SELECT mdl_user_info_data.data, mdl_user.firstname, mdl_user.lastname, mdl_user.id AS userid, SUM( mdl_quiz.fcpd ) AS cpdtotal
FROM mdl_grade_grades
INNER JOIN mdl_user ON mdl_grade_grades.userid = mdl_user.id
INNER JOIN mdl_grade_items ON mdl_grade_grades.itemid = mdl_grade_items.id
INNER JOIN mdl_quiz ON mdl_grade_items.itemname = mdl_quiz.name
INNER JOIN mdl_course ON mdl_grade_items.courseid = mdl_course.id
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE mdl_user_info_data.fieldid =1
AND mdl_grade_items.itemname IS NOT NULL
AND YEAR( FROM_UNIXTIME( mdl_grade_grades.timemodified ) ) =2013
GROUP BY mdl_user.id
To check for a timestamp value between a given datetime in the past, and the current datetime, something like this:
AND mdl_grade_grades.timemodified >= '2013-07-25 15:30'
AND mdl_grade_grades.timemodified < NOW()
Simply replace this line:
AND YEAR(FROM_UNIXTIME(mdl_grade_grades.timemodified)) = 2013
to:
AND FROM_UNIXTIME(mdl_grade_grades.timemodified)
BETWEEN '2012-01-01 12:00'
AND now()
It seems that you are storing unix timestamp in your timemodified column. You should consider changing it to timestamp type - this will allow to take advantage of index on that field. Now, your query (and this query as well) is slow because it has to compute FROM_UNIXTIME() on every row in that table and only then compare year or date.
UPDATE:
If you don't want to change types, using this should make your query work much faster (provided that there is an index on timemodified column):
AND mdl_grade_grades.timemodified
BETWEEN unix_timestamp('2012-01-01 12:00')
AND unix_timestamp(now())
try below query
SELECT mdl_user_info_data.data, mdl_user.firstname, mdl_user.lastname, mdl_user.id AS userid, SUM( mdl_quiz.fcpd ) AS cpdtotal
FROM mdl_grade_grades
INNER JOIN mdl_user ON mdl_grade_grades.userid = mdl_user.id
INNER JOIN mdl_grade_items ON mdl_grade_grades.itemid = mdl_grade_items.id
INNER JOIN mdl_quiz ON mdl_grade_items.itemname = mdl_quiz.name
INNER JOIN mdl_course ON mdl_grade_items.courseid = mdl_course.id
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE mdl_user_info_data.fieldid =1
AND mdl_grade_items.itemname IS NOT NULL
AND mdl_grade_grades.timemodified < date('d-m-Y')
GROUP BY mdl_user.id
You can create a Stored Procedure and pass the date as parameter to it.
Here I made it more flexible by adding end date too.
CREATE PROCEDURE `NewProc`(IN StartDate date,IN EndDate date)
BEGIN
SELECT mdl_user_info_data.data, mdl_user.firstname, mdl_user.lastname, mdl_user.id AS userid, SUM( mdl_quiz.fcpd ) AS cpdtotal
FROM mdl_grade_grades
INNER JOIN mdl_user ON mdl_grade_grades.userid = mdl_user.id
INNER JOIN mdl_grade_items ON mdl_grade_grades.itemid = mdl_grade_items.id
INNER JOIN mdl_quiz ON mdl_grade_items.itemname = mdl_quiz.name
INNER JOIN mdl_course ON mdl_grade_items.courseid = mdl_course.id
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE mdl_user_info_data.fieldid =1
AND mdl_grade_items.itemname IS NOT NULL
AND mdl_grade_grades.timemodified between StartDate and EndDate
GROUP BY mdl_user.id
END;
AND DATE(FROM_UNIXTIME(mdl_grade_grades.timemodified)) between '2013-01-01' and
DATE(NOW());