Update multiple rows with different values in a single query - MySQL - mysql

I'm new to MySQL.
I'm using this to update multiple rows with different values, in a single query:
UPDATE categories
SET order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END,
title = CASE id
WHEN 1 THEN 'New Title 1'
WHEN 2 THEN 'New Title 2'
WHEN 3 THEN 'New Title 3'
END
WHERE id IN (1,2,3)
I am using "WHERE" to improve performance (without it every row in the table would be tested).
But what if I have this senario (when I don't want to update title for id 2 and 3):
UPDATE categories
SET order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END,
title = CASE id
WHEN 1 THEN 'New Title 1'
END
WHERE id IN (1,2,3)
The above code will change the title for id 2 and 3 into "NULL"...
What is the right way to make the query, but skip updating title for id 2 and 3 and still keep the performance "WHERE id IN" gives ?
Maybe like this
UPDATE categories
SET order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END,
title = CASE id
WHEN 1 THEN 'New Title 1'
WHEN THEN
WHEN THEN
END
WHERE id IN (1,2,3)

Set title equal to itself when you don't want to update it to a different value.
UPDATE categories
SET order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END,
title = CASE id
WHEN 1 THEN 'New Title 1'
ELSE title
END
WHERE id IN (1,2,3)

UPDATE `table_name` SET `field_name1` = CASE `id`
WHEN '1' THEN 'value_1'
WHEN '2' THEN 'value_2'
WHEN '3' THEN 'value_3'
ELSE `field_name1`
END,
`field_name2`= CASE id
WHEN '1' THEN 'value_1'
WHEN '2' THEN 'value_2'
WHEN '3' THEN 'value_3'
ELSE `field_name2`
END

Related

Avoid duplicates on MySQL update

I have a many-to-many relation table like this
element_a
element_b
1
2
1
3
2
1
2
3
3
1
3
3
I want to replace element_a with id 2 by id 1
UPDATE mytable x
SET x.element_a = 1
WHERE x.element_a = 2;
Since there is an unique index on (element_a, element_b ), this will result with duplicates error.
How can I execute my query without MySQL Error 1062 ?
You can use an update with LEFT JOIN:
UPDATE mytable x
LEFT JOIN mytable t ON t.element_b = x.element_b AND 1 = t.element_a
SET x.element_a = 1
WHERE
x.element_a = 2 AND t.element_a IS NULL
If t.element_a IS NOT NULL then pair element_a, element_b already exists in your table. Thus adding t.element_a IS NULL in the WHERE clause prevents UPDATE in case of duplicates.
Demo here

MySQL: Add multiple columns after GROUP BY?

I am trying to do following:
SELECT
customer_entity.email,
customer_entity.website_id
FROM
customer_entity
INNER JOIN
(SELECT
email
FROM
customer_entity
GROUP BY email
HAVING COUNT(email) > 1) dupes
ON customer_entity.email = dupes.email
GROUP BY customer_entity.`entity_id`
ORDER BY customer_entity.email ;
Above query returns the result below:
email website_id
abe#abc.com 1
abe#abc.com 2
abe#abc.com 3
abe#abc.com 4
test#abc.com 1
test#abc.com 2
test#abc.com 4
xyz#abc.tv 1
xyz#abc.tv 2
xyz#abc.tv 3
But I want data in below format:
email website1 website2 website3 website4
abe#abc.com 1 2 3 4
test#abc.com 1 2 null 4
xyz#abc.tv 1 2 3 null
is it possible in this case?
Thanks
You can do conditional aggregation:
select
email,
max(website_id = 1) website_1,
max(website_id = 2) website_2,
max(website_id = 3) website_3,
max(website_id = 4) website_4
from customer_entity
group by email
having count(*) > 1
order by email
Note that this simplifies your original query - a self-join is not needed here.
Also, this puts 0/1 values in each column that indicates whether the given email exists for this website - I find that it is more meaningful than repeating the website id in the column.

Find items with maximum matching attributes

Here is my table structure - table name "propAssign"
(indexed) (composite index for attributeName and attributeValue)
productId attributeName attributeValue
1 Height 3
1 Weight 1
1 Class X1
1 Category C1
2 Height 2
2 Weight 2
2 Class X2
2 Category C1
3 Height 3
3 Weight 1
3 Class X1
3 Category C1
4 Height 4
4 Weight 5
4 Class X2
4 Category C3
What I want to do is, get list of productId, sorted by maximum matching attributes-value pair. In real table, I am using numeric ID of attribute name and value, I've used text here for easy representation.
So if I want to find matching products of productId=1, I want it to look for product which has maximum match (like Height=3, Weight=1, Class=X1 and Category=C1). There may not be any with 100% match (all 4 match) but if there are, they should come first, next comes productId which has any 3 attributes matching, then any 2, etc.
I could add more indexes if required, better if I don't have to since there are millions rows. It's MariaDB v10 to be exact.
Desired result - If I try to find matching product for productId=1, it should return following, in same order.
productId
-----------
3
2
Reason - 3 has all attributes matching with 1, 2 has some matches and 4 has no match.
You can use conditional aggregation to retrieve the productId's with the highest number of matches first.
select productId,
count(case when attributeName = 'Height' and attributeValue='3' then 1 end)
+ count(case when attributeName = 'Weight' and attributeValue='1' then 1 end)
+ count(case when attributeName = 'Category' and attributeValue='C1' then 1 end) as rank
from mytable
group by productId
order by rank desc
The query above returns all rows even with 0 matches. If you only want to return rows with 1 or more matches, then use the query below, which should be able to take advantage of your composite index:
select productId, count(*) as rank
from mytable
where (attributeName = 'Height' and attributeValue = '3')
or (attributeName = 'Weight' and attributeValue = '1')
or (attributeName = 'Category' and attributeValue = 'C1')
group by productId
order by rank desc

Sql for selecting from a table

I have a table like this
Id title parentId subparentId itemcategory
1 service cat1 0 0 C
2 service cat2 0 0 C
3 service subcat1 1 0 S
4 service subcat2 2 0 S
5 Item 1 1 0 I
5 Item 2 1 3 I
6 Item 3 2 4 I
I need an out put like this
service cat1
Item 1
service subcat1
Item 2
service cat2
service subcat2
Item 3
Ie, list shows the items ( category ,subcategory,Items ) in the order ascending order and if the items have any subcategory it should come under the subcategory
I think you should try something like:
SELECT
t1.title,
t2.title,
t3.title
FROM table t1
LEFT JOIN table t2 ON t1.id = t2.parentId
LEFT JOIN table t3 ON t2.id = t3.subparentId
WHERE t1.itemcategory = 'C'
AND t2.itemcategory = 'S'
AND t3.itemcategory = 'I'
;
For this case:
you should join your third table (item), directly with first table (service cat), not with second like in my example.
It's a complicated problem because there can be only one dimension in the sql query result.
But we can do a little trick here
SELECT *
FROM
(
SELECT
id,
title,
parentId,
subparentId,
itemcategory,
IF(
parentId = 0 AND subparentId = 0,
id * 10000,
IF(
subparentId = 0,
parentId * 10000 + 100 - id,
parentId * 10000 + subparentId * 100 + id
)
) AS itemOrder
FROM
table1
) allOrder
ORDER BY allOrder.itemOrder
SQL Fiddle: http://sqlfiddle.com/#!9/5f711/1/0
Increase the multiplier if you've got more rows.
Another way of doing it: http://sqlfiddle.com/#!9/bbf4d/1
(there is no need for a multiplier here)
select
concat(indent1, indent2, title) as title
from (
select
if(parentid>0,parentid,id) as id1,
case itemcategory
when 'C' then -1
when 'S' then id
when 'I' then if(subparentid>0,subparentid,0)
end as id2,
case itemcategory
when 'C' then -1
when 'S' then -1
when 'I' then id
end as id3,
case itemcategory
when 'C' then ''
when 'S' then '- - '
when 'I' then '- - '
end as indent1,
case itemcategory
when 'C' then ''
when 'S' then ''
when 'I' then '- - '
end as indent2,
title
from table1
order by id1,id2,id3
) allitems
Half of this code is for indenting so you get a nicer view. It's exactly like you requested (items are all indented equally even if they are not in the same level) but you can Fiddle with it yourself.
You can also add id1,id2,id3 in the first select to see how the order is done. The outside select is only done for viewing the title alone with indenting.
The result will be:
title
----------------------
service cat1
- - - - Item 1
- - service subcat1
- - - - Item 2
service cat2
- - service subcat2
- - - - Item 3

can anybody please give me an example of SELECT with CASE statement

i have table named chat_users with columns:
id | username | status | time_mod | views
Here is an example of UPDATE with CASE statement that works brilliantly:
$db->exec("UPDATE `proba13`.`chat_users`
SET `username` = CASE id
WHEN 4 THEN 'Jie'
WHEN 5 THEN 'Mie'
WHEN 6 THEN 'Pres'
END,
`status` = CASE id
WHEN 4 THEN '1'
WHEN 5 THEN '2'
WHEN 6 THEN '3'
END
WHERE id IN (4,5,6)");
QUESTION:
can anybody please give me an example of SELECT with CASE statement on the same table ?
regards and
Thank you in advance!
This will return the same results as your updated table (however, obviously without making any changes to it):
SELECT id,
CASE id
WHEN 4 THEN 'Jie'
WHEN 5 THEN 'Mie'
WHEN 6 THEN 'Pres'
ELSE username
END AS username,
CASE id
WHEN 4 THEN 1
WHEN 5 THEN 2
WHEN 6 THEN 3
ELSE status
END AS status,
time_mod,
views
FROM proba13.chat_users
Try this one
SELECT (CASE WHEN
id =4 THEN 'Jie'
WHEN id =5 THEN 'Mie'
WHEN id =6 THEN 'Pres'
END ) `username` ,
(CASE WHEN
id= 4 THEN '1'
WHEN id= 5 THEN '2'
WHEN id= 6 THEN '3'
END ) `status` FROM `chat_users`
WHERE id IN (4,5,6)