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;
Related
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).
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
Been looking into this for awhile. Hoping someone might be able to provide some insight. I have 3 tables. All of which I'm grabbing multiple columns, but the 3rd I need to limit the output to just the most recent timestamp entry, BUT still display multiple columns.
If I have the following data [ Please see SQL Fiddle ]:
http://sqlfiddle.com/#!2/84b91/6
The fiddle is a list of (names) in Table1(users), (job_name,years) in Table2(job), and then (score, timestamp) in Table3(job_details). All linked together by the users id.
I am definitely not great at MYSQL. I know I'm missing something.. possibly a series of JOINs. I have been able to get Table 1, Table 2 and one column of Table 3 by doing this:
select a.id, a.name, b.job_name, b.years,
(select c.timestamp
from job_details as c
where c.user_id = a.id
order by c.timestamp desc limit 1) score
from users a, job as b where a.id = b.user_id;
At this point, I can get multiple column data on the first two columns, limit the 3rd to one value and sort that value on the last timestamp...
My question is: How does one go about adding a second column to the limit? In the example in the fiddle, I'd like to add the score as well as the timestamp to the output.
I'd like the output to be:
NAME, JOB, YEARS, SCORE, TIMESTAMP. The last two columns would only be the last entry in job_details sorted by the most recent TIMESTAMP.
Please let me know if more information is required! Thank you for your time!
T
Try this:
select a.id, a.name, b.job_name, b.years, c.timestamp, c.score
from users a
INNER JOIN job as b ON a.id = b.user_id
INNER JOIN (SELECT jd.user_id, jd.timestamp, jd.score
FROM job_details as jd
INNER JOIN (select user_id, MAX(timestamp) as tstamp
from job_details
GROUP BY user_id) as max_ts ON jd.user_id = max_ts.user_id
AND jd.timestamp = max_ts.tstamp
) as c ON a.id = c.user_id
;
There are two tables:
SELECT id,customer FROM records;
SELECT user_id,call_date FROM call_history
Matching columns are:
records.id = call_history.user_id
The call_history table has call logs for customers.
There can be one or more call_history rows per customer.
I need to find when they called last time (for each customer).
For ex. userid=1 called twice, June 16 and July 20. Result must give me July 20, but I need to do the same for all customers from records table.
That is what I tried but it didn't work:
SELECT a.id, FROM_UNIXTIME(b.call_date,'%d/%m/%Y %H:%i') AS lastcall
FROM records a
INNER JOIN call_history b ON a.id=b.user_id
GROUP BY a.id ORDER BY b.call_date DESC;
Thank you.
Does this meet your requirements?
SELECT
r.id,
r.customer,
MAX(ch.call_date) AS lastcall
FROM
records AS r
INNER JOIN
call_history AS ch ON ch.user_id = r.id
GROUP BY
r.id,
r.customer
I know this is ordinary question but I need something more. I have an issue about getting values that are not inserted in one table.
Ok here are my tables:
name: importantDates; cols: id, date
name: inserts; cols: id, date, employe_id
My question: how to get missing values for each employe? Let's say I need missing inserts from employe with id=213?
So far, I wrote this, but it doesn't work yet as if there is insert for one worker in one day, it eliminates one day for all workers.
code:
SELECT i.date
FROM importantDates i
LEFT OUTER JOIN inserts s
ON i.date = DATE(s.date)
WHERE i.date BETWEEN '2013-1-1'
AND '2013-2-23'
AND s.date IS NULL;
Now how can I add checking for employe_id?
Thanks guys, if you need anything more I'm always available.
EDIT:
Here is sample:
Employe:
1. sam
2. mike
3. joe
importantDate:
1. 2013-01-01
2. 2013-01-02
3. ...
40. 2013-02-23
inserts:
1. 2013-02-01, 1
2. 2013-02-01, 2
3. 2013-02-01, 3
4. 2013-02-02, 3
5. 2013-02-03, 1
6. 2013-02-03, 2
7. 2013-01-12, 1
So, when I run query, I should get all "missing" inserts. For each employe I should get date and ID of employee when insert is missing. A lot of data but it is important to know which are not inserted and which are.
Assuming you have an employee table, try:
select sq.* from
(select e.employe_id, i.date
FROM importantDates i
CROSS JOIN employee e
WHERE i.date BETWEEN '2013-1-1' AND '2013-2-23') sq
LEFT OUTER JOIN inserts s
ON sq.date = DATE(s.date) and sq.employe_id = s.employe_id
WHERE s.date IS NULL;
If you don't have a separate employee table, you can simulate one by changing employee in the above query to be:
(select distinct employe_id from inserts) as e
Instead of LEFT OUTER JOIN use a simple LEFT JOIN and provide the dates correctly
SELECT
i.date
FROM importantDates i
LEFT JOIN inserts s
ON i.date = DATE(s.date)
WHERE i.date BETWEEN '2013-01-01'
AND '2013-02-23'
AND s.date IS NULL;
I'm not quite sure if I understand, what you're trying to achieve, but if you want to get every row from table_a which is not in table_b you can do this:
SELECT * FROM table_a
WHERE table_a.col NOT IN
(
SELECT col FROM table_b
)
So (if I understand you correctly) in your case:
SELECT i.date FROM importantDates i
WHERE i.date NOT IN
(
SELECT date FROM inserts WHERE employe_id = 213
)
AND i.date BETWEEN '2013-01-01' AND '2013-02-23';
For more documentation to the IN-clause see mysql documentation
UPDATE:
To get the corresponding employee you can alter the statement to this:
SELECT i.date, e.* FROM importantDates i
JOIN employees e
WHERE i.date NOT IN
(
SELECT s.date FROM inserts s WHERE s.employe_id = e.employe_id
)
AND i.date BETWEEN '2013-01-01' AND '2013-02-23';
However, this is not recommendable because the subquery is correlated to the mainquery.