MYSQL Trigger - Using SUM with JOIN - mysql

I have two tables:
A week table with columns week,Team_Number, and Points.
A Teams table with columns Team_Number and Session1Points.
I'd like to sum all of the Points from the week table where week column is between 1 and 9, then add that to the Teams table in the Session1Points column.
I've tried:
UPDATE Teams P
SET Session1Points =
(SELECT SUM(Points) from week
where week.Team_Number= P.Team_Number)
where P.Team_Number = New.Team_Number
that's not working. I'd like it to trigger after I update the week table. Do I need to Join first?

You can use a JOIN this way
UPDATE Teams P
INNER Join (SELECT
Team_Number
, SUM(Points) as team_sum
from week
group by Team_Number ) t on t.Team_Number=P.Team_Number
SET Session1Points = t.team_sum

Related

How to get distinct count of rows according to dates

Actually, i did counted distinct empid rows according to dates. But the problem is i get only one empid record of that specific dates.Please let me know how to get all empid records. Here is my sql query.
$sql = "
SELECT COUNT(DISTINCT subcount.empid) AS CountOf
, subcount.name
, subcount.date
, subcount.empid
, calendar.cdate
FROM subcount
, calendar
WHERE subcount.date = calendar.cdate
GROUP
BY subcount.date
";
Here is sql database.
For example, When you look at 2020-11-10 there are two empid with 10 and 7.
When i tried to get both records i get only empid 10 record or 7 record, though i need both record counts:
Here is the output:
Please help me on this.
I think what you are asking is to get list of employees with count of their submissions on a given date, this could show do it:
SELECT cnt.empid AS EmpId
, sc.Name
, cnt.`date` AS Timestamp
, cnt.CountOf AS SubmissionCount
FROM subcount AS sc
INNER JOIN
(
SELECT subcount.empid
subcount.`date`,
count(*) AS CountOf
FROM subcount
INNER JOIN calendar
ON subcount.`date` = calendar.cdate
GROUP BY
subcount.`date`, subcount.empid
) AS cnt
ON sc.empid == cnt.empid
It uses nested SELECT with GROUP BY to calculate count per employee (empid) and date (not only employee). Outer SELECT join nested SELECT to get subcount.Name piece of data which isn't retrieved in nested SELECT so it needs to be retrieved using outer SELECT.
GROUP BY ___ means result rows per ___. If you group by employee ID, you get one row per employee ID. If you want one row per employee ID and date, group by employee ID and date.
SELECT any_value(s.name), s.`date`, s.empid, c.cdate, count(*)
FROM subcount s
JOIN calendar c on c.cdate = s.`date`
GROUP BY s.`date`, s.empid
ORDER BY s.`date`, s.empid;
I expect a calendar table to have one row per date, so there is exactly one cdate for a result row. The name, however, can be different from row to row, so we must tell the DBMS, which to pick. With ANY_VALUE I tell it that I don't care which.

Sql query to add missing rows from another table

I have a table A (columns: id, year,month,amount) and table B( columns: id, year,month, amount=0).
Table A is the master table which have a same set of ids for each month for every year from 2011 to 2016.
In that some records are not present (like their is no record for 123456 id for 03 month and 2016 year and 468976 amountk), for that I want to add new record having id 123456, 03 in month and 2016 in year in table A and as it is a missing record amount will be 0.
The missing records are taken from table B which is having same set of ids from table A and for each id it is having every month for every year from 2011 to 2016, for each row amounts as 0.
Note:
1. In table A record s are not sorted and in table records are grouped by id, year and month.
2. If possible please make it normal sql queries instead of pl/sql. If not possible as I wanted please suggest your answer.
Thanks in advance........I hope you understsnd the problem statement.
You can generate the records using a cross join and some more logic:
select i.id, ym.year, ym.month
from (select distinct year, month from a) ym cross join
(select distinct id from b) i left join
a
on a.year = ym.year and a.month = ym.month and b.id = i.id
where a.id is null;
(I think I have the as and bs right. I'm not sure why two separate tables are mentioned in the question. It would seem that a is missing the records, so it is the only table needed. My best guess is that b is a subset of ids in a.)
Here is a version that does the insert:
insert into a(id, year, month)
select i.id, ym.year, ym.month
from (select distinct year, month from b) ym cross join
(select distinct id from b) i left join
b
on b.year = ym.year and b.month = ym.month and b.id = i.id
where b.id is null;

MYSQL left join and inner join

i have 3 tables
Employee => e_id (P.K), dep_id (F.k)
Department => d_id (P.K)
Attendance => id (P.K), date_of_absence (DATE), e_id_f (F.K)
i want to get the number of absent employees in certain department for a certain period.
i created a table called MyDates
CREATE TABLE MyDates (mydate date);
and this procedure to fill MyDates Table with Dates
CREATE PROCEDURE filldates(dateStart DATE, dateEnd DATE)
BEGIN
WHILE dateStart <= dateEnd DO
INSERT INTO MyDates (mydate) VALUES (dateStart);
SET dateStart = date_add(dateStart, INTERVAL 1 DAY);
END WHILE;
END;
then i called the procedure to fill MyDates with date CALL filldates('2017-01-01','2017-03-31');
Then i made this select statement :
select mydates.mydate, count(attendance.date_of_absence)
from mydates left join attendance on
mydates.mydate = attendance.date_of_absence
where mydates.mydate Between "2017-01-01" AND "2017-01-31"
group by mydates.mydate
This query gets what i need but for all departments, BUT for a certain department the number of rows is incorrect
select mydates.mydate, count(attendance.date_of_absence)
from mydates
left join attendance on mydates.mydate = attendance.date_of_absence
inner join employee on attendance.e_id_f = employee.e_id
where mydates.mydate Between "2017-01-01" AND "2017-01-31" AND employee.dep_id = 4
group by mydates.mydate;
This is a screenshot
IMG
There are 3 issues with your query I can see. The 1st 2 results in dropping the dates where no matching record is found, the 3rd potentially means that you get wrong counts:
inner join employee on attendance.e_id_f = employee.e_id - if there is no matching record for a day, then attendance.e_id_f will be null for that day. The inner join will eliminate this record from the resultset. Solution: make this join a left as well.
AND employee.dep_id = 4 - this would only keep records in the resultset, that have an employee record associated with it, so if you have a day with 0 absences, this criteria would eliminate it from the resultset. Solution: include this criteria in the join condition.
count(attendance.date_of_absence) - counts occurances from the attendance table, which will not be correct after adding the 2nd left join. Solution: use count(employee.dep_id) instead.
Modified query:
select mydates.mydate, count(employee.dep_id)
from mydates
left join attendance on mydates.mydate = attendance.date_of_absence
left join employee on attendance.e_id_f = employee.e_id AND employee.dep_id = 4
where mydates.mydate Between "2017-01-01" AND "2017-01-31" group by mydates.mydate
Alternative solution is to use nested joins, where you specifically instruct MySQL to execute attendance inner join employee join first. You still need to move the employee.dep_id = 4 condition to the join condition:
select mydates.mydate, count(attendance.date_of_absence)
from mydates
left join (attendance inner join employee)
on mydates.mydate = attendance.date_of_absence
and attendance.e_id_f = employee.e_id
and employee.dep_id = 4
where mydates.mydate Between "2017-01-01" AND "2017-01-31"
group by mydates.mydate
In the latter case the nested inner join ensures that only those attendance records are returned that belong to dep_id = 4 and these records are then left joined to your dates table. In this case there is no need to change the field you are counting.

Need a way to optimize the slow SQL Query?

I'm running an update query / sub-query on mySQL server and it takes 12 minutes to finish and I think it is not optimize enough.
Could someone think about anyway to optimize it, so it can run faster?
Thanks in advance.
UPDATE `TABLE_1` C
INNER JOIN(
SELECT Cust_No,
#current year sales
(SELECT SUM(`Sales`)
FROM `TABLE_2`
WHERE Year = 2016
AND Cust_No = p.Cust_No
) as CY_TOTAL_SALES,
# Get previou year sales
(SELECT SUM(`Sales`)
FROM `TABLE_2`
WHERE Year = 2015
AND Cust_No = p.Cust_No
) as PY_TOTAL_SALES
FROM `TABLE_2` p
WHERE Year >= 2015
AND Year <= 2016
) AS A ON C.`customer_number` = A.Cust_No
SET C.CY_TOTAL_SALES = A.CY_TOTAL_SALES,
C.PY_TOTAL_SALES = A.PY_TOTAL_SALES;
TABLE_1 contains 28,000 records ( customer_number field is unique and has indexed built)
TABLE_2 contains 250,000 records ( Cust_No is not unique,but has indexed built)
What it does is update TABLE_1 by joining Table_2 and use sub-query to sum up the total sales value for both years in TABLE_2 and then update the value back to TABLE_1 WHERE TABLE_1 customr number is matched with TABLE_2 Cust_no.
I can think of a couple of possible solutions.
Method one
Do just one subquery, don't do any correlated subqueries, and sum conditionally based on the year.
UPDATE TABLE_1 C
INNER JOIN (
SELECT Cust_No,
SUM(IF(Year=2015, Sales, 0)) AS PY_TOTAL_SALES,
SUM(IF(Year=2016, Sales, 0)) AS CY_TOTAL_SALES
FROM TABLE_2
WHERE Year IN (2015, 2016)
GROUP BY Cust_No
) AS S ON C.customer_number = S.Cust_No
SET C.PY_TOTAL_SALES = S.PY_TOTAL_SALES,
C.CY_TOTAL_SALES = S.CY_TOTAL_SALES;
Method two
Do no subqueries at all.
First, zero out the total sales for all customers:
UPDATE TABLE_1 C
SET C.CY_TOTAL_SALES = 0,
C.PY_TOTAL_SALES = 0;
Then do a join without using any subqueries or SUM() calls, and add each sale figure one at a time to the total sales for the customer.
UPDATE TABLE_1 AS C
INNER JOIN TABLE_2 AS S ON C.customer_number = S.Cust_No
SET C.CY_TOTAL_SALES = C.CY_TOTAL_SALES + IF(S.Year=2016, S.Sales, 0)
C.PY_TOTAL_SALES = C.PY_TOTAL_SALES + IF(S.Year=2015, S.Sales, 0)
WHERE S.Year IN (2015, 2016);
For both of these solutions, you'll want an index in TABLE_2 on the columns (Cust_No, Year, Sales).
In the meantime, I can explain a bit why your original query is so slow. Your subquery reads TABLE_2, which you say has 250,000 rows (I'll assume all the rows are in 2015-2016), and for each row it calculates the total sales for the corresponding customer. This means it calculates the same sums many times for each customer.
You're running 500,000 correlated subqueries! It's actually a miracle it only takes 12 minutes.
As it's doing this, it saves this entire result in a 250,000 row temporary table because of the subquery.
Then it joins the temporary table to TABLE_1, and for each customer sets the CY_TOTAL_SALES and PY_TOTAL_SALES. You don't know it, but it's setting the same totals many times for each customer.
Can't add comment because of new user reputation.
Without seeing the tables structures and the current indexes will be hard to tell how to optimize your current query.
Please edit your question to include the table structure (show create table).

MySQL query help (join, subselect)

I have 2 tables: orders and bookings.
The orders table contain unique orders from customers. Each customer has booked a locker for a period of 1 to 5 years and therefore the bookings table can contain 1 to 5 rows pr. order (1 row for each year). Each row in the booking table contains and end_date which is the same date every year (20XX-06-30).
I want to select all the orders where the corresponding final end_date in the bookings table is this year (2014-06-30).
SELECT DISTINCT orders.id
FROM orders,
bookings
WHERE orders.id = bookings.order_id
AND bookings.end_date = '2014-06-30'
The problem with this query is that it also selects the orders where the end_date in the booking rows continue the following years (2015-06-30, 2016-06-30 etc).
I am not sure I understood well, but here's a solution for what I understood, this should get you the order ids where there last end date (max) is 2014-06-30.
SELECT orders.id, MAX(bookings.end_date)
FROM orders INNER JOIN bookings
ON orders.id = bookings.order_id
GROUP BY bookings.order_id
HAVING MAX(bookings.end_date) = '2014-06-30'
Maybe join to the bookings again, checking for a larger booking date for the same order id:-
SELECT orders.id
FROM orders
INNER JOIN bookings ON orders.id = bookings.order_id
LEFT OUTER JOIN bookings2 ON orders.id = bookings2.order_id AND bookings2.end_date > bookings.end_date
WHERE bookings.end_date = '2014-06-30'
AND bookings2.end_date IS NULL