I understand the syntax here:
UPDATE table
SET column1 = expression1,
column2 = expression2,
...
WHERE conditions;
and here:
UPDATE table1
SET column1 = (SELECT expression1
FROM table2
WHERE conditions)
WHERE conditions;
...but what if I want to update
UPDATE table1
SET column1 = expression
if we get a particular result on a join between table1 and table2
which has WHERE conditions?
I can't seem to figure it out, and I get syntax errors in all of my attempts. Any advice greatly appreciated.
The syntax in MySQL is:
UPDATE table1 JOIN
table2
ON conditions
SET table1.column1 = table2.expression1
WHERE conditions;
What I do is write it as a SELECT statement first.
SELECT t.id
, t.col AS old_val
, s.expr AS new_val
FROM target_table t
JOIN source_table s
ON s.somecol = t.somecol
AND s.othercol < 1
WHERE s.something_else = 'abc'
In this example, t.col is the column that I (eventually) want to assign a new value to. (Used in the SELECT statement here, this just displays the value currently stored in the column.)
The expression s.expr represents the expression that returns the value I want to assign to col. This could be as simple as a column reference, or can be a more complex expression.
The rest of the statement are the normal FROM, JOIN, ON and WHERE clauses we're familiar with.
Once I have a SELECT statement that is working, I can convert that into an UPDATE statement by
replacing SELECT ... FROM (at the beginning of the statement) with the keyword UPDATE
adding a SET clause before the WHERE clause.
For example, I would convert the SELECT statement above to something like this, to assign the value of s.expr to t.col:
UPDATE target_table t
JOIN source_table s
ON s.somecol = t.somecol
AND s.othercol < 1
SET t.col = s.expr
WHERE s.something_else = 'abc'
This the approach that works for me. Writing it as a SELECT first allows me to test, muck with the conditions and expressions, and review to verify which rows are going to be updated, what values are being replaced, and what values are going to be assigned to each row.
Related
I was wondering if there's any way to add a subquery with a switch case to the form clause of my select query in order to select a table based on a condition.
For example:
select a.*
from (select (case when (table2.column = 'something')
then (table2.tablename1)
else (table2.tablename2)) as tablename
from table2
where table2.column2 = 'blabla'
limit 1
) a
I tried to write that in many variation & so far non of them worked.
On the most successful tryouts (when I got no mysql errors) it returned the name of the table as the result itself (for example: the value that's in table2.tablename2). I understand why it did that (because I selected everything from a select results...) but how can I use the tablename from the results in order to set the table on the main query?
Hope that make sense...
Any idea?
I've got a column "code" which may have a string of multiple values e.g. "CODE1&CODE2"... I just need the first one for my JOIN ... kind of like code.split("&")[0]
SELECT myTable.*, otherTable.id AS theID
FROM myTable INNER JOIN otherTable
ON myTable.(+++ code before the & +++) = otherTable.code
The value in myTable may also just be CODE1
SUBSTRING_INDEX will do exactly what you want - return the substring of your column up to the specified character:
SELECT
myTable.*,
otherTable.id AS theID
FROM myTable
INNER JOIN otherTable
ON SUBSTRING_INDEX(myTable.code, '&', 1) = otherTable.code
More info at: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html
And here's a fiddle demoing it: http://sqlfiddle.com/#!2/96a6e/2
Please note that this will be SLOW if you're joining many columns. You're not only eliminating the possibility of using an index, but performing a very slow string operation on every comparison. I wouldn't suggest using this on very large tables. If your data set is huge, you may want to consider rearchitecting your DB.
Tables i have
Table1 user_id, date
Table2 user_id, status
I need something like
UPDATE Table2
SET status = 2
WHERE user_id in ( {SELECT user_id FROM Table1 WHERE date > 0} )
In other words i need to see if date in table1 is more than 0000-00-00 then grab user_id of people who match this criteria and use them in table2 to set their status to 2.
Problem is that i need to do it for more than one user so request inside request does not work for me, it only works when there's one row in result.
I think what you've written should work, but what's with the curly braces? Just remove them to make it like this:
UPDATE Table2
SET status = 2
WHERE user_id in (SELECT user_id FROM Table1 WHERE date > 0)
According to the MySQL documentation, IN should work with a subquery.
The ANY keyword, which must follow a comparison operator, means “return TRUE if the comparison is TRUE for ANY of the values in the column that the subquery returns.”
When used with a subquery, the word IN is an alias for = ANY.
Are you using PHP or some other language to make SQL calls? If so, it might easier to just,
firstly: select user ids from table 1
secondly: loop through each row
thirdly: execute the update
Regards,
Mark
I'm working on a very limited MySQL environment (all MySQL calls are passed as array parameters). The problem is I don't know how to resolve an ambiguos condition.
In this environment all MySQL calls take this form:
SELECT value1,value2,...,valueN
FROM table1,table2,...,tableN
WHERE cond1 OP cond2 OP ... OP condN
That's not a problem until you have the same column names in table1 and table2. Imagine table1 has columns {a,b,z} and table2 has column names {c,d,f,z}. I can do this:
SELECT *
FROM table1, table2
WHERE a='3' AND table1.z='5'
Perfect but, one of the limitations is that I can't use table1.z format, just z='5' that produces a collision.
So, the question is: is there any way to prevent this ambiguosity without the use of table name prefix in the condition part? (for example, it will be great if there is a way to use only part of table2 or say that table1 has priority in case of ambiguity).
There is no way to avoid a collision if you can't qualify which table "myColumn" comes from.
Your constraints seem kind of silly... You're basically asking for valid result when you assert that you cannot write valid SQL....
Perhaps instead of SELECTing from table1, you would SELECT from a nested subquery in which you aliased the column names...
For example:
if table1 and table2 both have column "myColumn"
Rather than:
SELECT
*
FROM
table1,table2
WHERE myColumn = #value -- produces collision!
Could you say:
SELECT
*
FROM
(SELECT myColumn AS foo FROM table1) newTable1,
(SELECT myColumn AS bar FROM table2) newTable2
WHERE
foo = #value
This way you're not fully qualifying the tables in the outer WHERE clause but you are re-aliasing the columns inside the subqueries (thus making them into different names for the outer query)
This seems like a roundabout exercise though
EDIT:
http://thedailywtf.com/Articles/SQL-Sentences.aspx
"MySQL sentences?"
This is what i am doing
update t1 set x=a,y=b where a and b are obtained from (select query here)
I know the select query
The select query returns multiple results which are the same
When I use group by or distinct query execution slows down considerably
a and b are forward references so mysql reports an error
I want to set a equal to the value obtained in the first row and b equal to the value obtained in the first row for the respective columns, to avoid group by. I don't know how to refer to the first result from the select query.
How can i achieve all this?
LIMIT specifies the number of rows to return from the beginning of the result set:
SELECT * FROM t2 LIMIT 1; # Retrieve 1st row
LIMIT in your case is applied in the subquery in your from clause.
These linsk can help you out with update that uses a subquery:
Update with Subquery
Subqueries in MySQL, Part 1
you might be looking for something like...
update T1, (select Sub1.a, Sub1.b from YourSubQueryTable Sub1 where ... ) SubResult
set T1.a = SubResult.a,
T1.b = SubResult.b
where
Some T1.Criteria To be applied