Mysql: what to use instead of WITH statement or TEMPORARY tables? - mysql

Is there a way to store a select query into a table? I usually work with the WITH statement
but this is only possible with mysql 8+. I am currently using mysql 5.1. Therefore I tried to implement a temporary table but it is not possible to refer to a temporary table more than once in the same query (like the query below).
CREATE TEMPORARY TABLE test
SELECT TIMESTAMPDIFF(MONTH, MAX(L.period), CURDATE()) as timediff, L.contractID
FROM license L GROUP BY L.contractID;
UPDATE `contract` AS C
SET C.valid = CASE
WHEN (SELECT timediff FROM test AS T WHERE T.contractID = C.contractID) < 1 THEN 2
WHEN (SELECT timediff FROM test AS T WHERE T.contractID = C.contractID) = 1 THEN 1
WHEN (SELECT timediff FROM test AS T WHERE T.contractID = C.contractID) > 1 THEN 0
END;
DROP TEMPORARY TABLE test;

You could immediately remedy your problem by phrasing the update as a join:
UPDATE contract c
INNER JOIN test t
ON t.contractID = c.contractID
SET valid = CASE WHEN t.timediff < 1 THEN 2
WHEN t.timediff = 1 THEN 1
ELSE 0 END;
This approach gets around the problem of referring to the temporary table more than once.

Related

Query run time is taking more time in aurora mysql

I am facing performance issue on the below query. The row counts from each table provided below. I am creating group index before running the query.
select count(*) from temp1; - 3864797
select count(*) from temp2; - 36985
create index sav1dx1 on MIS.temp1 (tpid,origin_airport,dest_airport_1,dest_airport_2);
create index savidx3 on MIS.temp2(tpid,origin_airport,dest_airport_3);
CREATE temporary TABLE MIS.Tempfinal engine=Innodb as
select a.tpid,a.origin_airport,a.dest_airport_1,a.dest_airport_2,c.dest_airport_3,a.saving_1,a.saving_2,c.saving_3
from MIS.temp1 a join MIS.temp2 c on a.tpid = c.tpid and a.origin_airport = c.origin_airport
and a.dest_airport_1 <> c.dest_airport_3 and a.dest_airport_2 <> c.dest_airport_3
;
The above query is ending up with 583627364 rows in 3 hrs.
below is the explain output:
Savings_1 as temp1 and SaVings3 as temp2
explain
select a.tpid,a.origin_airport,a.dest_airport_1,a.dest_airport_2,c.dest_airport_3,a.saving_1,a.saving_2,c.saving_3
from MIS.Savings_1 a join MIS.SaVings3 c on a.tpid = c.tpid and a.origin_airport = c.origin_airport
and a.dest_airport_1 <> c.dest_airport_3 and a.dest_airport_2 <> c.dest_airport_3;
1|SIMPLE|c|ALL|savidx3|||37323|Using where
1|SIMPLE|a|ref|sav1dx1|sav1dx1|18|MIS.c.tpid,MIS.c.origin_airport|1|Using index condition; Using where
Thanks in advance.

Sql Server default value average of x rows

I have the following trigger running on MySQL:
CREATE DEFINER=`root`#`%` TRIGGER `before_insert` BEFORE INSERT ON `table` FOR EACH ROW SET
new.AVG_COLUMN1 = (SELECT avg(COLUMN1) FROM (SELECT COLUMN1 from table ORDER BY DateTimeCol DESC LIMIT 20) as COLUMN1_A),
new.AVG_COLUMN2 = (SELECT avg(COLUMN2) FROM (SELECT COLUMN2 from table ORDER BY DateTimeCol DESC LIMIT 20) as COLUMN2_A),
new.AVG_COLUMN3 = (SELECT avg(COLUMN3) FROM (SELECT COLUMN3 from table ORDER BY DateTimeCol DESC LIMIT 20) as COLUMN3_A)
Basically my goal here is to set a automatic, default value in the AVG_COLUMNx column, based on the last 20 entries in COLUMNx, whenever a new row is inserted. This is working fine in MySQL using the mentioned trigger.
I am in the process of migrating my project to Sql Server Express from MS, and I'm trying to do the same there. Does anyone have any good pointers as to how I could accomplish this? Using triggers, computed columns, etc?
Thanks for any input!
The logic would be different in SQL Server because it would be using inserted rather than new. Basically:
update t
set AVG_ROW1 = tt.avg1,
AVG_ROW2 = tt.avg2,
AVG_ROW3 = tt.avg3
from table t join
inserted i
on i.pk = t.pk outer apply
(select avg(Row1) as avg1, avg(Row2) as avg2, avg(Row3) as avg3
from (select top 20 t.*
from table t
order by DateTimeRow desc
) t
) tt;
You need some identifier(s) in the row to match the table to inserted. That is what pk stands for.

Retrieving rows that have 2 columns matching and 1 different

Below is my table called 'datapoints'. I am trying to retrieve instances where there are different instances of 'sensorValue' for the same 'timeOfReading' and 'sensorNumber'.
For example:
sensorNumber sensorValue timeOfReading
5 5 6
5 5 6
5 6 10 <----same time/sensor diff value!
5 7 10 <----same time/sensor diff value!
Should output: sensorNumber:5, timeOfReading: 10 as a result.
I understand this is a duplicate question, in fact I have one of the links provided below for references - however none of the solutions are working as my query simply never ends.
Below is my SQL code:
SELECT table1.sensorNumber, table1.timeOfReading
FROM datapoints table1
WHERE (SELECT COUNT(*)
FROM datapoints table2
WHERE table1.sensorNumber = table2.sensorNumber
AND table1.timeOfReading = table1.timeOfReading
AND table1.sensorValue != table2.sensorValue) > 1
AND table1.timeOfReading < 20;
Notice I have placed a bound for timeOfReading as low as 20. I also tried setting a bound for both table1 and table 2 as well but the query just runs until timeout without displaying results no matter what I put...
The database contains about 700mb of data, so I do not think I can just run this on the entire DB in a reasonable amount of time, I am wondering if this is the culprit?
If so how could I properly limit my query to run a search efficiently? If not what am doing wrong that this is not working?
Select rows having 2 columns equal value
EDIT:
Error Code: 2013. Lost connection to MySQL server during query 600.000 sec
When I try to run the query again I get this error unless I restart
Error Code: 2006. MySQL server has gone away 0.000 sec
You can use a self-JOIN to match related rows in the same table.
SELECT DISTINCT t1.sensorNumber, t1.timeOfReading
FROM datapoints AS t1
JOIN datapoints AS t2
ON t1.sensorNumber = t2.sensorNumber
AND t1.timeOfReading = t2.timeOfReading
AND t1.sensorValue != t2.sensorValue
WHERE t1.timeOfReading < 20
DEMO
To improve performance, make sure you have a composite index on sensorNumber and timeOfReading:
CREATE INDEX ix_sn_tr on datapoints (sensorNumber, timeOfReading);
I think you have missed a condition. Add a not condition also to retrieve only instances with different values.
SELECT *
FROM new_table a
WHERE EXISTS (SELECT * FROM new_table b
WHERE a.num = b.num
AND a.timeRead = b.timeRead
AND a.value != b.value);
you can try this query
select testTable.* from testTable inner join (
SELECT sensorNumber,timeOfReading
FROM testTable
group by sensorNumber , timeOfReading having Count(distinct sensorValue) > 1) t
on
t.sensorNumber = testTable.sensorNumber and t.timeOfReading = testTable.timeOfReading;
here is sqlFiddle
This query will return the sensorNumber and the timeOfReading where there are different values of sensorValue:
select sensorNumber, timeOfReading
from tablename
group by sensorNumber, timeOfReading
having count(distinct sensorValue)>1
and this will return the actual records:
select t.*
from
tablename t inner join (
select sensorNumber, timeOfReading
from tablename
group by sensorNumber, timeOfReading
having count(distinct sensorValue)>1
) d on t.sensorNumber=d.sensorNumber and t.timeOfReading=d.timeOfReading
I would suggest you to add an index on sensorNumber, timeOfReading
alter table tablename add index idx_sensor_time (sensorNumber, timeOfReading)

Update a MySQL table to double aggregate of a construct, which depends on the table itself

I need to update a table, but to get the new value it seems that I need to create a temporary table. The reason is that I need to calculate sum of the max. Can I do it?
The pseudocode looks like this:
UPDATE users u SET usersContribution = [CREATE TEMPORARY TABLE IF NOT EXISTS tmpTbl3 AS
(SELECT ROUND(max(zz.zachetTimestamp - d.answerDate)) as answerDateDiff
FROM zachet zz
JOIN discussionansw d ON d.zachetid=zz.zachetId and d.usersid=zz.usersId and
zz.zachetTimestamp > d.answerDate
WHERE zz.whoTalk=u.userid and
NOT EXISTS (SELECT * FROM discussionansw
WHERE zachetid=zz.zachetId and usersid=u.userid')
GROUP BY zz.zachetId)]
SELECT SUM(answerDateDiff) FROM tmpTbl3;"
I used a brackets to show the part, which have to be done, but ignored by UPDATE query...
I have both max and sum and I do not see a way to avoid tmp table. But if you can I we'll be glad to have such a solution.
I put here THE ANSWER, which I get with help of #flaschenpost and this post: SQL Update to the SUM of its joined values
CREATE TEMPORARY TABLE IF NOT EXISTS t0tmpTbl3 AS
(SELECT zz.whoTalk, ROUND(max(zz.zachetTimestamp - d.answerDate)) as answerDateDiff
FROM zachet zz
JOIN discussionansw d ON d.zachetid=zz.zachetId and d.usersid=zz.usersId and
zz.zachetTimestamp > d.answerDate
WHERE
NOT EXISTS (SELECT * FROM discussionansw WHERE zachetid=zz.zachetId and usersid=zz.whoTalk)
GROUP BY zz.zachetId);
UPDATE users u
JOIN (SELECT whoTalk, SUM(answerDateDiff) sumAnswerDateDiff
FROM t0tmpTbl3 GROUP BY whoTalk) t
ON u.usersId=t.whoTalk
SET u.usersContribution=sumAnswerDateDiff;
Could you just break it into two Queries?
drop temporary table if exists tmp_maxsumofsomething;
create temporary table tmp_maxsumofsomething
select max(), sum(), ...
from zachet z inner join discussionansw a on ...
group by...
;
update u inner join tmp_maxsumofsomething t on ... set u.... = t...
Temporary Tables are just visible in the connection where they have been created, so Thread Safety is given.
EDIT: As long as your Queries make any sense, you could try:
DROP TEMPORARY TABLE IF EXISTS tmpTbl3;
CREATE TEMPORARY TABLE tmpTbl3
SELECT zz.whoTalk as userId, ROUND(max(zz.zachetTimestamp - d.answerDate)) as answerDateDiff
FROM zachet zz, discussionansw d
WHERE d.zachetid=zz.zachetId
and d.usersid=zz.usersId and zz.zachetTimestamp > d.answerDate
# What do you mean ? by:
# and (SELECT count(*) FROM discussionansw
# WHERE zachetid=zz.zachetId and usersid=u.userid) = 0
# Think about a reasonable WHERE NOT EXISTS clause!
GROUP BY zz.whoTalk
Then you have your Temp-Table to join to:
update users u
inner join tmpTbl3 tm on u.userId = tm.userId
set u.usersContribution = tm.answerDateDiff
If you are brave enough to write an application needing those queries, you should not be scared to learn a bit more of some concepts of SQL and MySQL. You are here for the exploration of concepts, not to hire Programmers for free.

Updating sort keys after delete

I have a table which has a field sort_id. In this field there are numbers from 1 to n, that define the order of the data sets.
Now I want to delete some elements and afterwards I want to reorder the table. Therefore I need a query that "finds" the gaps and changes the sort_id field according to the modifications.
Sure, I could do something like this:
SELECT sort_id FROM table WHERE id = 5
Then save the sort_id and afterwards:
DELETE FROM table WHERE id = 5
UPDATE table SET sort_id = sort_id - 1 WHERE sort_id > {id from above}
But I'd like to do the reordering process in one step.
Mladen and Arvo have good ideas, but unfortunately in MySQL you can't SELECT and UPDATE the same table in the same statement (even in a subquery). This is a known limitation of MySQL.
Here's a solution that uses MySQL user variables:
SET #i := 0;
UPDATE mytable
SET sort_id = (#i := #i + 1)
ORDER BY sort_id;
For what it's worth, I wouldn't bother doing this anyway. If your sort_id is used only for sorting and not as a kind of "row number," then the rows are still in sorted order after you delete the row where id=6. The values don't necessarily have to be consecutive for sorting.
for sql server 2005:
this is how you get the new sequence:
SELECT row_number() over(order by sort_id) as RN
FROM table
updating the table means you should join that select to your update:
update t1
set sort_id = t2.RN
FROM table t1
join (SELECT row_number() over(order by sort_id) as RN FROM table) t2
on t1.UniqueId = t2.UniqueId
I don't know MySQL syntax variations and cannot test query live, but something like next should give you at least an idea:
update table t1
set sort_id = (select count * from table t2 where t2.sort_id <= t1.sort_id)