MySQL update multiple rows using arrays - mysql

How can we update multiple rows at once in case of below stated data
studentId = [1,2,5,7,9]
marks = [25, 22, 27, 30, 24]
what will be the MySQL statement, if we want to update studentId 1 with 25 marks, studentId 2 with 22 marks, studentId5 with 27 marks and so on.
Please note: Have to update in 1 query only.
Thanks in advance :)

If you are using MySql 8.0+ you can create a CTE that returns the rows of the ids that you want to update and their marks and join it to the table:
WITH cte(studentId, marks) AS (VALUES
ROW(1, 25), ROW(2, 22), ROW(5, 27), ROW(7, 30), ROW(9, 24)
)
UPDATE tablename t
INNER JOIN cte c ON c.studentId = t.studentId
SET t.marks = c.marks
See the demo.
For previous versions, instead of the CTE you can join a query that uses UNION ALL:
UPDATE tablename t
INNER JOIN (
SELECT 1 studentId, 25 marks UNION ALL
SELECT 2, 22 UNION ALL
SELECT 5, 27 UNION ALL
SELECT 7, 30 UNION ALL
SELECT 9, 24
) c ON c.studentId = t.studentId
SET t.marks = c.marks
See the demo.

You could run one simple query five times, with different values:
UPDATE MyTable SET marks = ? WHERE studentId = ?
The idea is that you would write a loop in some application code, so you process the first element from each of your arrays. Then the second element of both arrays, and so on. For example in PHP:
$studentId = [1,2,5,7,9];
$marks = [25, 22, 27, 30, 24];
$stmt = $pdo->prepare("UPDATE MyTable SET marks = ? WHERE studentId = ?");
for ($i=0; $i<5; ++$i) {
$stmt->execute([$marks[$i], $studentId[$i]]);
}
From its earliest versions, SQL was always intended to be used in combination with an application language. Other languages have variables and loops and conditions and functions, which complement SQL. The easiest solution is to use these languages together.
If you really want to write a single UPDATE statement to update all five, it's possible, but it's really not as clear.
UPDATE MyTable
SET marks = CASE studentId
WHEN 1 THEN 25
WHEN 2 THEN 22
WHEN 5 THEN 27
WHEN 7 THEN 30
WHEN 9 THEN 24
END
WHERE studentId IN (1,2,5,7,9);
There are other clever ways of doing it in one statement, but all these solutions are hard to modify or maintain. They are needlessly complex.
I recommend doing it the simple way.

Related

Mysql filter by multiply ids

I can't finish writing query to filter row by multiply ids. Here is query:
select distinct `storage_file`.*, `storage_tag`.`id` as `tid` from `storage_file`
inner join `storage_file_tag` on `storage_file`.`id` = `storage_file_tag`.`storage_file_id`
inner join `storage_tag` on `storage_tag`.`id` = `storage_file_tag`.`storage_tag_id`
where `storage_file`.`user_id` = 17 and `storage_file`.`deleted_at` is null and
`storage_tag`.`id` IN(13,17);
So the result is without group by statement is:
So.. I need result only with two records which contain tid 13 and 17
And when i replace "IN(13,17)" with storage_tag.id = 13 AND storage_tag.id = 17 - i get no records at all
How can i write subquery which will work like a + b but not a OR b ?
I'm not sure what you do exactly but it seams, that the distinct is not working as you expect, because you select "*" from storage_file, as there are different values in the columns of storage_file, the result is distincted but over all selected columnns and so more the two are selected.
You can replace
... AND id IN (11,22)
with
... AND ( id = 11 OR id = 12)
You need the parentheses because WHERE operator precedence rules are very simple.
Of course,
... AND id = 11 AND id = 12
never returns anything because the id cannot have two different values at the same time.

SQL query to see if condition is met and nothing else

I have a MySQL table that looks like this:
What I'm trying to find out is if column anaID has the value of 22 or 23, and no other value is assigned for anaID for that subID/sampleID combination.
something like
select * from anaData where subID='2020-04-21-17' and sampleID='crazy2'
and
(anaID=22 or anaID=23)
and
andID <> ??anything else??
I can query out all the matches and loop through them and have program logic that decides, but I'm hoping this can be done in a query.
You can use not exists:
select *
from anaData a
where subID = '2020-04-21-17' and
sampleID = 'crazy2' and
not exists (select 1
from anaData a2
where a2.subID = a.subID and a2.sampleID = a.sampleID and
a2.anaID not in (22, 23)
);
It turns out that you don't need anaID in (22, 23) in the outer query. The exists takes care of that.
This works if at least one anaID 22 or 23 exist:
select subID, sampleID
from anaData
where subID='2020-04-21-17'
and sampleID='crazy2'
group by subID, sampleID
having
sum(case when anaID in (22, 23) then 1 else -100 end) > 1
If you want both 22 and 23 switch to = 2 (assuming that the combination subID/sampleID/anaID is unique.
This can also be used without WHERE-conditions.

PHP order by clause with array as order by statement

I got a array with a query
This array is ordered by criteria.
Now I want to make a new query
Sample
$array = (987, 2661, 12, 789, 54);
And I want in this order by array selecting articles
select * from article a.number WHERE (a.number IN ($array))
How can I realize that this result is ordered by $array ids?
Thx you 4 answer guys :)
edit :
Article Table:
id, name etc..
Property Table:
id, article_id, name, value
1, 10, journey_days, 2
2, 30, journey_days, 1
3, 40, journey_days, 5
1, 10, stars, 2
2, 10, stars, 4
3, 10, stars, 0
4, 10, stars, 1
I join both tables, but as you can see the property have more then one value per column for one article.
I need to join the Property table to the article table and get all Values there are related from property table to the article, if I make a where clause I just get stars or journey_days.
How can I realise this? to select all property.name values with a where or on clause?
Hope you guys understand my question
Use implode:
$s = implode(",", $array);
$q = "select * from article a.number WHERE (a.number IN ($s))";
You could construct a CASE expression and order by that, but it's probably better to do this in PHP, outside of the database.
... ORDER BY CASE a.number
WHEN 987 THEN 1
WHEN 2661 THEN 2
WHEN 12 THEN 3
WHEN 789 THEN 4
WHEN 54 THEN 5
END;
Or you could use the FIND_IN_SET function:
.... ORDER BY FIND_IN_SET(a.number, "987,2661,12,789,54");

MySQL Table UNION ISSUE

I'm trying to unite two tables in MySQL, the query I'm using is:
SELECT qa_invoicesitems.item_code, qa_invoicesitems.item_unitprice, qa_invoicesitems.item_subtotal, qa_invoicesitems.item_discount,
qa_invoicesitems.item_total
FROM qa_invoicesitems
RIGHT JOIN qa_invoicesitems_returnlog USING (item_code)
WHERE invoice_code = 17
UNION
SELECT qa_invoicesitems_returnlog.item_code, qa_invoicesitems_returnlog.item_unitprice, qa_invoicesitems_returnlog.item_subtotal,
qa_invoicesitems_returnlog.item_discount, qa_invoicesitems_returnlog.item_total
FROM qa_invoicesitems_returnlog
LEFT JOIN qa_invoicesitems USING (item_code)
WHERE returnlog_code = 9
But I can not behold the desired result.
A graphical example ..
Anyone have any idea how I can get this result?
NOTE: qa_invoicesitems_returnlog Replaces the data.
The codes: 1234, 1585, 23 are taken from (qa_invoicesitems_returnlog), because they exist in both tables, the rest are simply displayed.
Based upon your comments & your image, I'm going to say you want:
all the rows in table 2 where qa_invoicesitems_returnlog = 9
all the rows in table 1 where invoice_code = 17, except for those rows w/ item_id's that are already present in the output from table 2.
So, writing that out as a union, give you:
SELECT qa_invoicesitems_returnlog.item_code as item_code,
qa_invoicesitems_returnlog.item_unitprice as item_unitprice,
qa_invoicesitems_returnlog.item_subtotal as item_subtotal,
qa_invoicesitems_returnlog.item_discount as item_discount,
qa_invoicesitems_returnlog.item_total as item_total
FROM qa_invoicesitems_returnlog
WHERE qa_invoicesitems_returnlog.returnlog_code = 9
UNION
SELECT qa_invoicesitems.item_code as item_code,
qa_invoicesitems.item_unitprice as item_unitprice,
qa_invoicesitems.item_subtotal as item_subtotal,
qa_invoicesitems.item_discount as item_discount,
qa_invoicesitems.item_total as item_total
FROM qa_invoicesitems
WHERE qa_invoicesitems.invoice_code = 17
AND NOT EXISTS (SELECT * FROM qa_invoicesitems_returnlog qir2
WHERE qir2.returnlog_code = 9
and qir2.item_code = qa_invoicesitems.item_code)
The key is the NOT EXISTS clause that excludes from the results from table 1 (qa_invoiceitems) that are already present in the output from table 2 and have a matching item_code.
Why are you using a UNION? I think the following is equivalent to your query:
SELECT qa_invoicesitems.item_code, qa_invoicesitems.item_unitprice,
qa_invoicesitems.item_subtotal, qa_invoicesitems.item_discount,
qa_invoicesitems.item_total
FROM qa_invoicesitems RIGHT JOIN
qa_invoicesitems_returnlog
USING (item_code)
WHERE invoice_code = 15 or returnlogcode = 8
The LEFT and RIGHT joins are doing the same thing because the tables are reversed.

Where A=1 AND A=2 returns 0 row problem - (Short Mysql question)

I have the following table (id, Tag) with the following values
(1, 17)
(1, 31)
(2, 17)
(3, 31)
When I query the following
"SELECT id FROM table WHERE 1 AND Tag=17 AND Tag=31"
I expected it to return (id)
(1)
But it doesn't. (returns 0 row)
What's wrong here?
For any particular row the tag can't be both 17 and 31. You need
SELECT id
FROM table
WHERE Tag in (17, 31)
GROUP BY id
HAVING COUNT(DISTINCT Tag) = 2
Machines are logic and do what you asked them to do... your expectations are wrong in this case.
Tag 17 AND tag 31 conditions according to boolean math should be satisfied simultaneous to produce results.
You are asking for a row with the value of Tag being 17 AND 31...at the same time. You probably want this (Also, WHERE 1 is unneeded):
SELECT DISTINCT id FROM table WHERE Tag=17 OR Tag=31
EDIT: After reading some other answers, I decided to go crazy with this.
SELECT A.id
FROM table A JOIN table B ON A.id = B.id
WHERE A.Tag=17 AND B.Tag=31;