Specific query optimization on MySQL - mysql

I have a table into MySQL DB (version 5.1.x), with the name table. Its columns are:
id, double_col_index1, double_col_index2, flag, col_index_1, a_date_col, col_index_2, col_index_3 with the following indexes:
a single index on double_col_index1 and double_col_index2
an index on col_index_1
an index on col_index_2
an index on col_index_3
Now, I have the following query:
UPDATE `table` t1 INNER JOIN
(SELECT t2.id FROM `table` t2
WHERE t2.double_col_index1 = 'fake_value1'
AND t2.double_col_index2 = 'fake_value2'
AND flag = 'true'
AND (col_index_1 = '' OR a_date_col < '1920-11-10 00:00:00')
AND
(SELECT count(t3.id) FROM `table` t3
WHERE t3.double_col_index1 = 'fake_value1'
AND t3.double_col_index2 = 'fake_value2'
AND t3.col_index_2 = t2.col_index_2
AND t3.col_index_3 = 'fake_col_index_3_1') > 0
AND
(SELECT count(t4.id) FROM `table` t4
WHERE t4.double_col_index1 = 'fake_value1'
AND t4.double_col_index2 = 'fake_value2'
AND t4.col_index_2 = t2.col_index_2
AND t4.col_index_3 = 'fake_col_index_3_2') > 0) tbl
ON t1.id = tbl.id SET col_index_1 = 'fake_value';
Question: I would need to improve this query, to give a better performance if possible. Would anyone have any suggestions on this?
One idea would be to use instead of INNER JOIN an t1.id in (.... What is your advice on this?

Basic idea of the join would be to do it as follows.
UPDATE `table` t1
INNER JOIN
(
SELECT t2.id
FROM `table` t2
INNER JOIN
(
SELECT DISTINCT col_index_2
FROM `table`
WHERE double_col_index1 = 'fake_value1'
AND double_col_index2 = 'fake_value2'
AND col_index_3 = 'fake_col_index_3_1'
) t3
ON t3.col_index_2 = t2.col_index_2
INNER JOIN
(
SELECT DISTINCT col_index_2
FROM `table`
WHERE double_col_index1 = 'fake_value1'
AND double_col_index2 = 'fake_value2'
AND col_index_3 = 'fake_col_index_3_2'
) t4
ON t4.col_index_2 = t2.col_index_2
WHERE t2.double_col_index1 = 'fake_value1'
AND t2.double_col_index2 = 'fake_value2'
AND flag = 'true'
AND (col_index_1 = '' OR a_date_col < '1920-11-10 00:00:00')
) tbl
ON t1.id = tbl.id
SET col_index_1 = 'fake_value';
This may be quite a bit quicker but will depend on many factors. MySQL will not use indexes for joining against the sub queries.
However there is a big issue with this (and your existing query) in MySQL
http://dev.mysql.com/doc/refman/5.7/en/update.html
Currently, you cannot update a table and select from the same table in a subquery.
There is a way round this, by doing a query on the sub query

Related

Update with Subquery non relational table

I have the follow sql query but when I execute It gives me a message error: Unknown column 't1.ip' in 'where clause'.
If I hard code t1.ip in subquery just for testing, It works perfectly.
UPDATE
report_a t1,
(SELECT
location.country, region.name, location.city
FROM
geoip
INNER JOIN
location
ON
geoip.locId = location.locId
INNER JOIN
region
ON
region.country = location.country
AND
region.region = location.region
WHERE
INET_ATON(t1.ip) BETWEEN startIpNum AND endIpNum
LIMIT 1) AS t2
SET
t1.country = t2.country,
t1.city = t2.city,
t1.state = t2.name;
Someone have any idea how i can do this query?
Thanks
You are looking for a join. I am a bit unclear on what the LIMIT 1 is supposed to be doing. I moved that into the outer query, although that might not be correct:
UPDATE report_a t1,
(SELECT location.country, region.name, location.city, startIpNum, endIpNum
FROM geoip INNER JOIN
location
ON geoip.locId = location.locId INNER JOIN
region
ON region.country = location.country AND
region.region = location.region
) glr
ON INET_ATON(t1.ip) BETWEEN glr.startIpNum AND glr.endIpNum
SET t1.country = t2.country,
t1.city = t2.city,
t1.state = t2.name
LIMIT 1;
As I think about it, you probably do not want the LIMIT 1. Why would there be multiple matches to the subquery?

MySQL - is a sub query what's needed here?

I currently have such a query:
SELECT
sec_to_time(avg(t1.sessiontime)) as aloc,
count(*) as calls
FROM
table1 AS t1
inner join
table2 as t2 ON t1.destination = t2.prefix
WHERE
t1.card_id = '101'
AND
t1.terminatecauseid = 1
group by t1.destination
Example result:
The 'calls' data is bound to 't1.terminatecauseid = 1' (meaning only answered calls)
I'd like to have a percentage of answered calles from the total calls made.
the same query without the condition (t1.terminatecauseid = 1) will give me the total calls made.
I'd like to know what is the best way to add another column called 'Average Success Rate' that will do:
total-calls*successful-calls/100
Is a subquery what's needed here? or a brand new and different query?
SELECT
sec_to_time(avg(t1.sessiontime)) as aloc,
sum(t1.terminatecauseid = 1) * 100 / count(*) as Average_Success_Rate,
sum(t1.terminatecauseid = 1) as calls
FROM
table1 AS t1
inner join
table2 as t2 ON t1.destination = t2.prefix
WHERE
t1.card_id = '101'
group by t1.destination

Update table on itself MySQL

I can't figure out how to make this query run.... I want to update the table so that dependent on the uuid it grabs the lowest of the 'last_updated' and updates the 'created_on' ... I keep getting 'cant specify target table' although I don't know why =/ Is it a recursion issue?
UPDATE dlp.address AS t1
SET created_on = (SELECT MIN(last_updated)
FROM dlp.address AS t2
WHERE t1.addressuuid = t2.addressuuid);
UPDATE dlp.address AS t1
INNER JOIN
(
SELECT addressuuid, MIN(last_updated) minDate
FROM dlp.address
GROUP BY addressuuid
) AS t2
ON t1.addressuuid = t2.addressuuid
SET t1.created_on = t2.minDate
You can use :
UPDATE dlp.address AS t1
, (SELECT addressuuid, MIN(last_updated) AS minDate
FROM dlp.address GROUP BY addressuuid) AS t2
SET t1.created_on = t2.minDate
WHERE t1.addressuuid = t2.addressuuid

Update mysql rows with value extracted from counting another table

I have the following query:
SELECT int_intrebari.id, COUNT( id_raspuns ) AS nr_raspunsuri
FROM int_intrebari, int_raspunsuri
WHERE int_intrebari.id = int_raspunsuri.id
GROUP BY id
Is it possible to update first table with nr_raspunsuri from the query, without writing a foreach statement?
You can UPDATE with JOIN like so:
UPDATE int_intrebari i1
INNER JOIN
(
SELECT id, COUNT( id_raspuns ) AS nr_raspunsuri
FROM int_intrebari
GROUP BY id
) i2 ON i1.id = i2.id
SET i1.nr_raspunsuri = i2.nr_raspunsuri
You can do it like -
update int_intrebari left join int_raspunsuri on int_intrebari.id =int_raspunsuri.id
set int_intrebari.column_to_update = int_raspunsuri.column_from_update_second_table
UPDATE
(SELECT int_intrebari.id, COUNT( id_raspuns) AS nr_raspunsuri
FROM int_intrebari, int_raspunsuri
WHERE int_intrebari.id = int_raspunsuri.id
GROUP BY id) t1,
int_raspunsuri t2
SET
t2.nr_raspunsuri=t1.nr_raspunsuri
WHERE
t1.id=t2.id

Mysql update using values from select

I have two queries. The first will return multiple rows:
SELECT parent_entry_id,child_entry_id FROM exp_playa_relationships WHERE parent_field_id = '34';
...And I would like to use the values (parent_entry_id,child_entry_id) and incorporate them into this query, replacing 'x' and 'y', and do it for each row returned by the first query.
UPDATE exp_channel_data AS t1,
(
SELECT field_id_46,field_id_47 FROM exp_channel_data WHERE entry_id = 'x') AS t2
SET t1.field_id_60 = t2.field_id_46, t1.field_id_61 = t2.field_id_47
WHERE t1.entry_id = 'y';
I think I need to use another JOIN, but I can't figure out how to implement one in my example. Any help would be much appreciated.
I think this is what you're after:
UPDATE exp_playa_relationships AS t0
JOIN exp_channel_data AS t1
ON t1.entry_id = t0.child_entry_id
JOIN exp_channel_data AS t2
ON t2.entry_id = t0.parent_entry_id
SET t1.field_id_60 = t2.field_id_46
, t1.field_id_61 = t2.field_id_47
Try this query
UPDATE exp_channel_data a1 INNER JOIN exp_playa_relationships a ON a1.entry_id = a.child_entry_id
INNER JOIN exp_channel_data b ON a.parent_entry_id = b.entri_id
SET a1.field_id_60 = b.field_id_46, ta1.field_id_61 = b.field_id_47
WHERE parent_field_id = '34'
Thanks all for your replies. The working syntax is:
UPDATE exp_channel_data AS t1,
(
SELECT
entry_id as ei2, child_entry_id, parent_entry_id, field_id_46 as f46,field_id_47 as f47
FROM
exp_channel_data JOIN exp_playa_relationships ON entry_id=child_entry_id AND parent_field_id = 34) AS t2
SET t1.field_id_60 = f46, t1.field_id_61 = f47
WHERE t1.entry_id=parent_entry_id;
Or in a more classic syntax, you need to adjust to your own foo & bar attributes, but use something like the following:
update exp_channel_data t1
set (t1.field_id_60,t1.field_id_61) = (
select t2.field_id_46 , t2.field_id_47
from exp_channel_data t2
where 1=1
and t2.entry_id = 'x'
and /* ENTER YOUR t1-t2 join condition here */
)
where 1=1
and t1.entry_id = y
;
But since you are MySQL I don't believe it supports compound subquery. As such:
update exp_channel_data t1
set t1.field_id_60 = (
select t2.field_id_46
from exp_channel_data t2
where 1=1
and t2.entry_id = 'x'
and /* ENTER YOUR t1-t2 join condition here */
) , t1.field_id_61 = (
select t3.field_id_47
from exp_channel_data t3
where 1=1
and t3.entry_id = 'x'
and /* ENTER YOUR t1-t3 join condition here */
)
where 1=1
and t1.entry_id = y
;