MYSQL: subquery into a table updated in the main query - mysql

I'd like do something like this:
In table TAGS find a row with name='someName', and remeber it's id
In the same table find another row with someCondition and set in this row col refference=the id from above
Tried to do this using a subquery, but mysql refused saying I can't subquery a table that I'm updating in the main query.
How can I otherwise implement the above idea?
Thank you

Convert your subquery to a join and then UPDATE:
You can also perform UPDATE operations covering multiple tables. However, you cannot use ORDER BY or LIMIT with a multiple-table UPDATE. The table_references clause lists the tables involved in the join. Its syntax is described in Section 12.2.8.1, “JOIN Syntax”. Here is an example:
UPDATE items,month SET items.price=month.price
WHERE items.id=month.id;
The preceding example shows an inner join that uses the comma operator, but multiple-table
UPDATE statements can use any type of join permitted in SELECT statements, such as LEFT JOIN.

you can do this
update TAGS set
reference =
(select my_id from
(select id as my_id from TAGS where name='someName')
as SUB_TAGS)
where someCondition;
Not advisable though.
Edit#1 You can avoid the sub-queries altogether -- as taspeotis rightly mentioned, by joining the same table with the criteria. Here goes the code for that:
UPDATE
TAGS t1, TAGS t2
SET
t1.reference = t2.id
WHERE
t2.name = 'someName'
AND
t1.someField = someCondition;
This is a better approach.

Related

MYSQL update from another table with multiple entries

I have seen a bunch of helpful answers about updating table values from a different table with multiple values based on a timestamp using a MAX() subquery.
e.g. Update another table based on latest record
I was wondering how this compares with doing an ALTER first and relying on the order in the table to simplify the UPDATE. Something like this:
ALTER TABLE `table_with_multiple_data` ORDER BY `timestamp` DESC;
UPDATE `table_with_single_data` as `t1`
LEFT JOIN `table_with_multiple_data` AS `t2`
ON `t1`.`id`=`t2`.`t1id`
SET `t1`.`value` = `t2`.`value`;
(Apologies for the pseudocode but I hope you get what I'm asking)
Both achieve the same for me but don't really have a big enough data set to see any difference in speed.
Thanks!!
You would normally use a correlated subquery:
UPDATE table_with_single_data t1
SET t1.value = (select t2.value
from table_with_multiple_data t2
where t2.t1id = t1.id
order by t2.timestamp desc
limit 1
);
If your method happens to work, that is just happenstance. Even if MySQL respected the ordering of tables, such ordering would not survive the join operation. Not to mention the fact that there is no guarantee on *which * value is assigned when there is multiple matching rows.

Include all of these commands in one big MySQL statement?

For an assignment, I have to include all of these keywords in one big MySQL statement: select, from, where, group by, order by, inner join, insert, update, delete.
Obviously all but the last 3 are easy to include in 1 statement.
However, I'm having a problem with using union on 2 SQL statements (one with select, etc. and the other with insert).
For example, I have:
SELECT * FROM Database
INNER JOIN (O_Database INNER JOIN ...)
ON ...
GROUP BY ...
ORDER BY ...
UNION
INSERT INTO Database (...) VALUES (...)
But I run into errors with using UNION this way. Is there a simple statement that includes all of these keywords?
I see no solution to put DELETE in there. You can build a select statement with all the stuff required and use this in an INSERT ON DUPLICATE KEY UPDATE Statement. But DELETE? No. In Oracle this would be possible by using the MERGE statement, but this is not available in MySQL. So I guess, there is no solution to the task given.
INSERT INTO ...
SELECT ... -- using from, where, group by, order by, and inner join here
ON DUPLICATE KEY
UPDATE ...
Well, you can do something like
INSERT INTO A
SELECT whatever FROM B;
or
UPDATE A
INNER JOIN (SELECT * FROM B ) C ON A.id = C.id
SET A.whatever = C.whatever;
or
DELETE
FROM A WHERE A.whatever IN (SELECT whatever FROM B);
But you can not combine DELETE and UPDATE or UPDATE and INSERT. Just one of the operations with a SELECT.

mysql "where" without using "from"

Is this valid syntax? It seems like the from clause should be implied when explicitly naming the table and column, table.column.
SELECT
distinct concat(\"Question \", q.place) as question
FROM q
INNER JOIN test
ON test.id = q.test
AND q.id NOT IN (
SELECT responses.question
where //Is this Valid or do I need to select from a table explicitly?
responses.tester = tester.id)
INNER JOIN test
ON test.id = testingsession.test
INNER JOIN tester
ON tester.test = test.id
WHERE
tester.id = :id
ORDER BY
questions.position
In MySQL it's valid to have a SELECT without a FROM clause, but that returns singleton row (similar to using the special DUAL table from Oracle) and you can't use a WHERE clause.
In your case, the SELECT query is returning values from a table, so you need a FROM clause to reference that table.
To answer your question, no, what you have is not valid.
NOTES:
For performance, I'd use an anti-join pattern over a NOT IN (correlated_subquery).
There's several problems in the syntax:
You've got the test table referenced twice. At least one of those references is going to be assigned an alias.
You've got a reference to testingsession.test, but there is no testingsession row source in your query.
The query references questions.positions in the ORDER BY clause, but there is no questions row source.
That is not valid! You cannot use a column from a table that is not included in your FROM / JOIN part (here responses.tester). You will have to join responses too.

Is this query well written? I am fairly new at this and am wondering if there is a better way to write it

UPDATE table1
INNER JOIN table2
ON table1.var1=table2.var1
SET table1.var2=table2.var2
My table has about 975,000 rows in it and I know this will take a while no matter what. Is there any better way to write this?
Thanks!
If the standard case is that table1.Var2 already is equal to table2.var2, you may end up with an inflated write count as the database may still update all those rows with no functional change in value.
You may get better performance by updating only those rows which have a different value than the one you desire.
UPDATE table1
INNER JOIN table2
ON table1.var1=table2.var1
SET table1.var2=table2.var2
WHERE (table1.var2 is null and table2.var2 is not null OR
table1.var2 is not null and table2.var2 is null OR
table1.var2 <> table2.var2)
Edit: Nevermind... MySQL only updates on actual changes, unlike some other RDBMS's (MS SQL, for example.)
Your query:
UPDATE table1 INNER JOIN
table2
ON table1.var1 = table2.var1
SET table1.var2 = table2.var2;
A priori, this looks fine. The major issue that I can see would be a 1-many relationship from table1 to table2. In that case, multiple rows from table2 might match a given row from table1. MySQL assigns an arbitrary value in such a case.
You could fix this by choosing one value, such as the min():
UPDATE table1 INNER JOIN
(select var1, min(var2) as var2
from table2
group by var1
) t2
ON table1.var1 = t2.var1
SET table1.var2 = t2.var2;
For performance reasons, you should have an index on table2(var1, var2). By including both columns in the index, the query will be able to use the index only and not have to fetch rows directly from the table.

How to optimize a MySQL update which contains an "in" subquery?

How do I optimize the following update because the sub-query is being executed for each row in table a?
update
a
set
col = 1
where
col_foreign_id not in (select col_foreign_id in b)
You could potentially use an outer join where there are no matching records instead of your not in:
update table1 a
left join table2 b on a.col_foreign_id = b.col_foreign_id
set a.col = 1
where b.col_foreign_id is null
This should use a simple select type rather than a dependent subquery.
Your current query (or the one that actually works since the example in the OP doesn't look like it would) is potentially dangerous in that a NULL in b.col_foreign_id would cause nothing to match, and you'd update no rows.
not exists would also be something to look at if you want to replace not in.
I can't tell you that this will make your query any faster, but there is some good info here. You'll have to test in your environment.
Here's a SQL Fiddle illuminating the differences between in, exists, and outer join (check the rows returned, null handling, and execution plans).