MySQL Query Optimisation - Single query restriction - mysql

With my restricted access, I can run only a single query at a time. Quite often I have to run a query similar to the one below for tens of IDs. One by one it turns to be a pretty time-consuming task.
UPDATE table1
SET columnA = X,
columnB = (SELECT max(columnC) FROM table2 WHERE id = <ID>)
WHERE id = <ID>
Ideally I would like to use something like id in {id1, id2, ...}, however both instances of ID must be the same.
I am trying to modify the query so it can process number of ID in a single query.
==================================================
SOLUTION (quite simple actually):
UPDATE table1
SET columnA = X,
columnB = (SELECT max(columnC) FROM table2 WHERE id = table1.id)
WHERE id in (id1, id2, ...)

Try belwo. Please do required changes because I have explained just way to do
UPDATE table1 as t1 INNER
JOIN (
SELECT id
, Max(columnC) As maxval
FROM table12
GROUP
BY id
) As t2 ON t1.id= t2.id
SET columnA = t1.x
FROM columnB = t2.maxval
WHERE id = <ID>

you might want to try this.
for T-SQL:
UPDATE a
SET a.columnA = X,
a.columnB = max(b.columnC)
FROM table1 a INNER JOIN table b ON a.id = b.id
WHERE a.id IN ('ID','HERE',...)
UPDATE
for MySQL:
UPDATE table1 a INNER JOIN
(SELECT id, Max(columnC) As iMax
FROM table12
GROUP BY id) b ON a.id = b.id
SET a.columnA = X,
a.columnB = b.iMax
WHERE a.id IN ('ID','HERE',...)
REFERENCE

Related

Update of single table using join

I have a select using two tables via a join. I need to update first table using the second table field. Select as follows
select R.f1, Z.f2,R.f3
FROM
(select * From Table1 where f2<>'xx' and f3='z') R inner join
(select * From Table2 where f3='xx') Z
ON R.f1⁼Z.f1 and R.f4=Z.f4
How could I update correspond to same select of Table1 (SET R.f2=Z.f2)?
UPDATE
(select * From Table1 where f2<>'xx' and f3='z') R inner join
(select * From Table2 where f3='xx') Z
ON R.f1⁼Z.f1 and R.f4=Z.f4
SET R.f2=Z.f2
When I tried, I get a response that
target table R of the UPDATE is not updatable
You can use a join in update statements using the following....
update t
set t.Column = value
from Table t
inner join OtherTable ot on t.Id = ot.TID
where somecondition = true.
You should perform the update on table1 and join it to the second subquery. The conditions on table1 from the first subquery could be applied in the where clause:
UPDATE table1 r
JOIN (SELECT * FROM table2 WHERE f3 = 'xx') z ON r.f1 ⁼ z.f1 AND r.f4 = z.f4
SET r.f2 = z.f2
WHERE r.f2 <> 'xx' AND r.f3 = 'z'

MYSQL Performance Tuning with group by clause

I have a query like this.
SELECT count(*)
FROM table1 e
WHERE e.column1=1
AND e.id IN
(SELECT MAX(ID)
FROM table2 A
WHERE A.column1=1
AND A.date=CURDATE()
GROUP BY A.column2);
When I run this query it is taking too much of time as I am having thousands of records. How can I tune the query to perform better.
Thanks in advance.
EDIT: column2 in table2 is id of Table1
Change in (. . .) To use join instead. Like
SELECT count(*)
FROM table1 AS e
Inner join
(
SELECT MAX(ID)
FROM table2 A
WHERE A.column1 = 1
AND A.date = CURDATE()
GROUP BY A.column2
) t2 on e.id = t2.id
WHERE e.column1 = 1
Maybe:
SELECT count(*)
FROM table1 e
WHERE e.column1=1
AND EXISTS
(SELECT *
FROM table2 A
WHERE A.column1=1
AND A.date=CURDATE()
AND A.ID = e.id);

complex sql statement to different rows

I have a simple table which has 4 fields:
indexID
UserID
text_1
IsFinal
This table may have multiple values for each UserID, and IsFinal field can have only a single value 1 or 0.
What I'm trying to do is to make a select statement which will return the user IDs if IsFinal only equal 0. The problem there may be multiple records for the same userID, some having IsFinal equal to 0 and only 1 with IsFinal equal to 1.
My problem here is this: for every UserID, if it has a record with Isfinal = 1, I want to ignore all records with the same UserID, otherwise I want to return its records. I don't know if that can be done by SQL statement only or not.
Seems like you want an anti-join, i.e. you first need to establish which user IDs have IsFinal = 1, then use that result set to return all user IDs not in that list.
There are various ways to implement an anti-join.
NOT IN:
SELECT *
FROM atable
WHERE UserID NOT IN (
SELECT UserID
FROM atable
WHERE IsFinal = 1
);
NOT EXISTS:
SELECT *
FROM atable t1
WHERE NOT EXISTS (
SELECT *
FROM atable t2
WHERE t1.UserID = t2.UserID
AND t2.IsFinal = 1
);
LEFT JOIN + WHERE IS NULL:
a)
SELECT *
FROM atable t1
LEFT JOIN (
SELECT *
FROM atable
WHERE IsFinal = 1
) t2 ON t1.UserID = t2.UserID
WHERE t2.UserID IS NULL;
b)
SELECT *
FROM atable t1
LEFT JOIN atable t2
ON t1.UserID = t2.UserID AND t2.IsFinal = 1
WHERE t2.UserID IS NULL;
It may so happen that they will be equally efficient in your database, but it still may be a good idea to test each of them to at least avoid ending up with one that performs worse than the others.
I think this is what you are looking for:
SELECT a.*
FROM translations a
INNER JOIN (SELECT UserID FROM translations WHERE IsFinal = 1) b
ON a.UserID = b.UserID
WHERE IsFinal = 0;
TRY ( not tested )
SELECT t1.* FROM table t1
INNER JOIN table t2 USING(indexID)
WHERE t1.IsFinal <>1
GROUP BY t1.UserID

MySQL alternative to using two nested queries

I am trying to learn about MYSQL Joins but am having trouble figuring this one out. I want to get all rows in table1 where the userID is in a relationship with the given user.
table2 contains user relationships so the userID can either be in iduser1 field or iduser2 field
I have the following query that gives me the correct results:
set #userID = 91;
SELECT * FROM table1
WHERE (iduser IN (SELECT iduser1 FROM table2 WHERE iduser2 = #userID)
OR (iduser IN (SELECT iduser2 FROM table2 WHERE iduser1 = #userID)))
table1:
iduser FK
table2:
iduser1 FK
iduser2 FK
I have been told that nested queries in MySQL have a bad reputation when it comes to performance and I am sure I could probably do this same query using JOINS somehow but I just cant figure it out especially as there is an OR statement because the table1.iduser can be in either table2.iduser1 OR table2.iduser2
How can I join the same table twice?
Given this expression:
set #userID = 91;
SELECT * FROM table1
WHERE (iduser IN (SELECT iduser1 FROM table2 WHERE iduser2 = #userID)
OR (iduser IN (SELECT iduser2 FROM table2 WHERE iduser1 = #userID)))
Using EXISTS, you can reduce that two subqueries into following:
set #userID = 91;
SELECT * FROM table1 x
WHERE EXISTS(
select * from table2 z
where (z.user2 = #userID and iduser1 = x.iduser)
OR (z.user1 = #userID and iduser2 = x.iduser)
)
The OR might slowdown your query, it doesn't necessarily short-circuit in RDBMS. In that case, you should try to short-circuit it by using CASE WHEN. I had a query that took 5 seconds to execute when using OR, but took sub-zero second when I translated it to CASE WHEN:
set #userID = 91;
SELECT * FROM table1 x
WHERE EXISTS(
select * from table2 z
where
CASE WHEN z.user2 = #userID THEN
IF(z.iduser1 = x.iduser, 1, 0)
CASE WHEN z.user1 = #userID THEN
IF(z.iduser2 = x.iduser, 1, 0)
END = 1
)
Boolean expression automatically cast to integer(either 0(false) or 1(true)), so you can also do it like this:
set #userID = 91;
SELECT * FROM table1 x
WHERE EXISTS(
select * from table2 z
where
CASE WHEN z.user2 = #userID THEN
z.iduser1 = x.iduser
CASE WHEN z.user1 = #userID THEN
z.iduser2 = x.iduser
END = 1
)
Or this:
set #userID = 91;
SELECT * FROM table1 x
WHERE EXISTS(
select * from table2 z
where
CASE WHEN z.user2 = #userID THEN
z.iduser1 = x.iduser
CASE WHEN z.user1 = #userID THEN
z.iduser2 = x.iduser
END
)
If you are not using MySQL, you shall do it like this:
set #userID = 91;
SELECT * FROM table1 x
WHERE EXISTS(
select * from table2 z
where
CASE WHEN z.user2 = #userID THEN
CASE WHEN z.iduser1 = x.iduser THEN 1 END
CASE WHEN z.user1 = #userID THEN
CASE WHEN z.iduser2 = x.iduser THEN 1 END
END = 1
)
Let me object that MySQL handles poorly not only subqueries but EXISTS, and OR, too.
Therefore I would suggest a different approach to the problem.
Since the parameter in the queries is known thanks to a user variable, we can prepare joinable queries.
set #userID = 91;
SELECT DISTINCT T1.* FROM table1 T1
LEFT JOIN (SELECT iduser1 FROM table2 WHERE iduser2 = #userID) T21
ON (T1.iduser = T21.iduser1)
LEFT JOIN (SELECT iduser2 FROM table2 WHERE iduser1 = #userID) T22
ON (T1.iduser = T22.iduser2)
;
As you can see, EXISTS and OR are perfectly implemented by LEFT JOIN that searches for each match, if any, with other users in the second table.
Obviously the same user in table1 could find several matches, hence a DISTINCT might do the trick and remove duplicates.
I suggest you to use JOIN wherever you can in order to exploit MySQL.

mysql select multiple and join query

I have a complicated MYSQL query question here. I try my best to explain my problem.
I have 4 tables. mid is a foreign key between the tables. table4 is NOT a compulsory table source. However I like it returns all the rows even there are no match data from table4. So that I write a query script as following.
I'm not sure is it the logic way to write such query script but what I know that the syntax is wrong.
SELECT *
FROM table1, table2, table3,
(SELECT xx
FROM table4
RIGHT JOIN table1 ON table1.mid = table4.mid)
WHERE table1.mid = table2.mid
AND table1.mid = table3.mid
AND tt = 'a'
AND type = 1
GROUP BY table1.mid
ORDER BY xx DESC, table1.name ASC;
You have to do a left join between table1 & table4:
SELECT *
FROM table1
JOIN table2 ON table1.mid = table2.mid
JOIN table3 ON table1.mid = table3.mid
LEFT JOIN table4 ON table1.mid = table4.mid
WHERE tt = 'a'
AND type = 1
GROUP BY table1.mid
ORDER BY xx DESC, table1.name ASC;