Update with SubQuery from same table - mysql

Is it possible to update using a subquery from the same table?
I get this error:
1093 - You can't specify target table 'tasks' for update in FROM clause
update tasks SET completed_form = 'y' AND all_forms_in = 'y' where EID in (select EID from tasks WHERE completed_form = 'y' AND all_forms_in = 'n' group by EID having count(*) > 1);
UPDATE
I found that if I wrapped the query in another select it worked. As referenced here: MySQL Error 1093 - Can't specify target table for update in FROM clause
update tasks SET all_forms_in = 'y' where EID in (SELECT * FROM (select EID from tasks WHERE completed_form = 'y' AND all_forms_in = 'n' group by EID having count(*) > 1)AS b);

MySQL supports JOIN in UPDATE statements, so you could do this without subqueries. You'd have to join to two distinct rows with your completed criteria to simulate the count(*) > 1.
UPDATE tasks AS t1
INNER JOIN tasks AS t2
ON (t1.EID = t2.EID AND t2.completed_form = 'y' AND t2.all_forms_in = 'n')
INNER JOIN tasks AS t3
ON (t1.EID = t3.EID AND t3.completed_form = 'y' AND t3.all_forms_in = 'n'
AND t2.primary_key <> t3.primary_key)
SET t1.completed_form = 'y',
t1.all_forms_in = 'y';

Related

If else in Mysql Update query

I need a query to update some fields in a table based on count of another field.
Update
bank_sample_map
LEFT JOIN
sample_details ON bank_sample_map.sample_track_id = sample_details.sampletrack_id
LEFT JOIN
order_details ON order_details.sample_detail_id = sample_details.sample_id
LEFT JOIN
test_details ON test_details.test_detail_id = order_details.test_detail_id
SET
bank_sample_map.sample_id = sample_details.sample_id, bank_sample_map.order_id = order_details.order_number,
bank_sample_map.testid = test_details.test_id,bank_sample_map.test_cost = test_details.test_cost
WHERE
bank_sample_map.sample_id IS NULL
AND bank_sample_map.order_id IS NULL
AND bank_sample_map.testid IS NULL
AND (select count(order_number) < 2 from order_details where sample_detail_id = sample_details.sample_id);
If(count(order_number) < 2) I need to update sample_id,order_id,testid,test_cost
Else update sample_id only.
How to change my query to satisfy this condition.

Specific query optimization on 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

How do I put an 'if clause' in an SQL string?

So here's what I want to do on my MySQL database.
I would like to do:
SELECT *
FROM itemsOrdered
WHERE purchaseOrder_ID = '#purchaseOrdered_ID'
AND status = 'PENDING'
If that would not return any rows, which is possible through if(dr.HasRows == false), I would now create an UPDATE in the purchaseOrder database:
UPDATE purchaseOrder
SET purchaseOrder_status = 'COMPLETED'
WHERE purchaseOrder_ID = '#purchaseOrder_ID'
How would I be able to make this process a little shorter?
For your specific query, you can do:
UPDATE purchaseOrder
SET purchaseOrder_status = 'COMPLETED'
WHERE purchaseOrder_ID = '#purchaseOrder_ID' and
not exists (SELECT *
FROM itemsOrdered WHERE purchaseOrder_ID = '#purchaseOrdered_ID' AND status = 'PENDING'
)
However, I might guess that you are looping at a higher level. To set all such values, try this:
UPDATE purchaseOrder
SET purchaseOrder_status = 'COMPLETED'
WHERE not exists (SELECT 1
FROM itemsOrdered
WHERE itemsOrdered.purchaseOrder_ID = purchaseOrder.purchaseOrdered_ID AND
status = 'PENDING'
limit 1
)
You can use the multiple-table UPDATE syntax to effect an ANTI-JOIN between purchaseOrder and itemsOrdered:
UPDATE purchaseOrder p LEFT JOIN itemsOrdered i
ON p.purchaseOrder_ID = i.purchaseOrder_ID
AND i.status = 'PENDING'
SET p.purchaseOrder_status = 'COMPLETED'
WHERE p.purchaseOrder_ID = '#purchaseOrder_ID'
AND i.purchaseOrder_ID IS NULL
Since MySQL doesn't support if exists(*Your condition*) (*Write your query*), you can achieve an 'if clause' by writing like this:
(*Write your insert or update query*) where not exists (*Your condition*)
You can also use the following query to check if the record exists and then update it:
if not exists(select top 1 fromFROM itemsOrdered
WHERE purchaseOrder_ID = '#purchaseOrdered_ID'
AND status = 'PENDING' )
Begin
UPDATE purchaseOrder
SET purchaseOrder_status = 'COMPLETED'
WHERE purchaseOrder_ID = '#purchaseOrder_ID
End
Select FROM t1
WHERE s11 > ANY
(SELECT col1,col2 FROM t2
WHERE NOT EXISTS
(SELECT * FROM t3
WHERE ROW(5*t2.s1,77)=
(SELECT 50,11*s1 FROM t4 UNION SELECT 50,77 FROM
(SELECT * FROM t5) AS t5)));
if not exists(select top 1 fromFROM itemsOrdered
WHERE purchaseOrder_ID = '#purchaseOrdered_ID'
AND status = 'PENDING' )
Begin
UPDATE purchaseOrder
SET purchaseOrder_status = 'COMPLETED'
WHERE purchaseOrder_ID = '#purchaseOrder_ID
End
after sql server 2008 provide Merge to insert,update and delete operation based on single match statement, also that allows you to join. below sample example might be helps you.
MERGE Target AS T
USING Source AS S
ON (T.EmployeeID = S.EmployeeID)
WHEN NOT MATCHED BY TARGET AND S.EmployeeName LIKE 'S%'
THEN INSERT(EmployeeID, EmployeeName) VALUES(S.EmployeeID, S.EmployeeName)
WHEN MATCHED
THEN UPDATE SET T.EmployeeName = S.EmployeeName
WHEN NOT MATCHED BY SOURCE AND T.EmployeeName LIKE 'S%'
THEN DELETE
OUTPUT $action, inserted.*, deleted.*;
like this you can insert, update and delete in one statements.
and for more information you can refer official documents on
https://technet.microsoft.com/en-us/library/bb522522(v=sql.105).aspx
If the table contains millions of records then the following query will work fast.
UPDATE PO
SET PO.purchaseOrder_status = 'COMPLETED'
FROM purchaseOrder PO
LEFT OUTER JOIN itemsOrdered IOD ON IOD.purchaseOrder_ID = PO.purchaseOrdered_ID and IOD.status = 'PENDING'
WHERE IOD.purchaseOrder_ID IS NULL
You can declare a variable holding the number of returned results on select query.
You can then run the update statement if this variable is more than 0
Declare #ResultCount int
SELECT #ResultCount = count(*) FROM itemsOrdered WHERE purchaseOrder_ID = '#purchaseOrdered_ID' AND status = 'PENDING'
If #ResultCount > 0
UPDATE purchaseOrder SET purchaseOrder_status = 'COMPLETED' WHERE purchaseOrder_ID = '#purchaseOrder_ID'

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

sql error(1242) : sub query returns more than 1 row

i have two tables a_daily and o_daily_lcsgeneration:
i am trying this query :
update a_daily
set
a_daily.Turbine_Generation =
(
select sum(o_daily_lcsgeneration.Turbine_Generation)
from o_daily_lcsgeneration
where o_daily_lcsgeneration.Location = 1
group by o_daily_lcsgeneration.Date
)
but received the above error saying sub query more than 1 row
remove the GROUP BY clause
UPDATE a_daily
SET a_daily.Turbine_Generation =
(
SELECT sum(o_daily_lcsgeneration.Turbine_Generation)
FROM o_daily_lcsgeneration
WHERE o_daily_lcsgeneration.Location = 1
)
it causes the query to return more than one value of you have multiple dates.
UPDATE 1
UPDATE a_daily a
INNER JOIN
(
select g.Date, sum(g.Turbine_Generation) totalSum
from o_daily_lcsgeneration g
where g.Location = 1
group by g.Date
) b ON a.date = b.date
SET a.Turbine_Generation = b.totalSum
WHERE a.location = 1
or
UPDATE a_daily a
LEFT JOIN JOIN
(
select g.Date, sum(g.Turbine_Generation) totalSum
from o_daily_lcsgeneration g
where g.Location = 1
group by g.Date
) b ON a.date = b.date
SET a.Turbine_Generation = COALESCE(b.totalSum, 0)
Run the subquery and you'll see that it returns more than one row. You are grouping the results by date, so the SUM expression calculates the value for every day. You could re-write the query as follow:
UPDATE a_daily
SET a_daily.Turbine_Generation = (SELECT SUM(o_daily_lcsgeneration.Turbine_Generation)
FROM o_daily_lcsgeneration
WHERE o_daily_lcsgeneration.Location = 1
AND o_daily_lcsgeneration.Date = 'YYYY-MM-DD'
GROUP BY o_daily_lcsgeneration.Date)
or (for a total sum of all events):
UPDATE a_daily
SET a_daily.Turbine_Generation = (SELECT SUM(o_daily_lcsgeneration.Turbine_Generation)
FROM o_daily_lcsgeneration
WHERE o_daily_lcsgeneration.Location = 1)
update a_daily
set
a_daily.Turbine_Generation = (
select sum(o_daily_lcsgeneration.Turbine_Generation)
from o_daily_lcsgeneration where o_daily_lcsgeneration.Location = a_daily.Location
group by o_daily_lcsgeneration.Date
)