mySQL delete row with count(*) GROUP and HAVING - mysql

I have this query where i get all double entries with the same articleID and the categoryID = 2153
Now i want to delete this rows. But this seems not to work directly.
So i tried it with subquery, but when i use IN i would need a subquery which returns only the id. But that's also not possible.
How can i delete the rows from this query?
SELECT id, articleID, categoryID, count(*) AS count
FROM `s_articles_categories`
GROUP BY articleID
HAVING count(*) > 1 AND categoryID = 2153

Assuming that the id is the primary key for the table s_articles_categories You could use a join on the subselect result.
To delete all rows :
delete r.*
from s_articles_categories r
INNER JOIN (
SELECT id, articleID, categoryID, count(*) AS count FROM
`s_articles_categories` r
GROUP BY articleID
HAVING count(*) > 1 AND categoryID = 2153
) t on t.id = r.id

If you want to delete all duplicates but keep one of them in each group, then you can use the following query :
DELETE FROM `s_articles_categories` s
WHERE s.categoryID = 2153 AND EXISTS (
SELECT 1
FROM `s_articles_categories` s1
WHERE s1.articleID = s.articleID AND s1.categoryID = s.categoryID AND s1.id < s.id
)

I would recommend writing this as:
delete ac
from s_articles_categories ac join
(select articleId, categoryid, min(id) as min_id
from s_articles_categories
where categoryID = 2153
group by articleId, categoryid
) ac2
on ac2.articleId = ac.articleId and
ac2.categoryid = ac.categoryid and
ac.id > ac2.min_id

Related

How do i retrieve data from table using group by having foll0wing condition

List of all countries having more than 2 COVID-19 affected males.
select * from country
where country_id in(select country_id
from(select country_id, count(*)
from person
where Gender="Male"
and virus_id=(select virus_id
from virus
where virus_name="crona_virus"
)
group by country_id
having count(*)>2
)as tbl
);
I do get the results but those are not desired.
IN could be replaced by join and sub queries replaced by join
select country.*
from country
join
(select country_id, count(*)
from person
join virus on person.virus_id = virus.virus_id and virus_name = 'corona_virus'
group by country_id having count(*)>2
)as tbl
on country.country_id = tbl.country_id;

Mysql update count union based on first table

I would like to update a table (category) to save how many items are affected to this category (or sub-category from this parent category)
I have this:
update category as a
set nb_items = (select count(distinct item_id) from (
select item_id from item_category where category_id = a.id
union all
select item_category.item_id
from category as sub_cat
inner join item_category
on item_category.category_id = sub_cat.id
where sub_cat.parent_id = a.id
) as tmp
)
where category.parent_id is null
But it complains that a.id is unknown.
I will use a workaround, but I am curious to know how to do this (using a single statement, no temporary tables)
Thank you all!
Best,
EDIT:
Following #Akina 's advice, I got this query, which seemed to work fine!
update category as a
inner join (
select count(distinct item_id) as total, category_id as cat
from item_category
group by cat
union all
select count(distinct item_category.item_id) as total, top_cat.id as cat
from category as top_cat
inner join category as sub_cat
on sub_cat.parent_id = top_cat.id
inner join item_category
on item_category.category_id = sub_cat.id
group by cat
) as tmp
on tmp.cat = a.id
set a.nb_items = tmp.total
where a.parent_id is null;
I'm not 100% sure it removes duplicates, but looking at the results it seems ok.
Thanks again to #Akina !

Limit results to 1 row for each group in subquery

as a result of the execution of this query, situations are possible when two rows have the same minimum price, but i still need to select one. I understand perfectly well that the standard limit cannot be dispensed with here. I do not have enough knowledge to understand from which side to approach the solution of this issue. Thank you in advance for your attension.
UPDATE offers t1
SET t1.deleted_at = NOW()
WHERE t1.id
NOT IN
(
SELECT f.id
FROM (
SELECT name, MIN(net_price) as minprice
FROM offers
WHERE
supplier_id = (SELECT id FROM suppliers WHERE name = 'somename')
group BY name
)
AS x inner join (SELECT * FROM offers) AS f ON f.name = x.name AND f.net_price = x.minprice
)
AND
t1.supplier_id = (SELECT id FROM suppliers WHERE name = 'somename');
I don't know somehowe, but this works for me:
UPDATE offers t1
SET t1.deleted_at = NOW()
WHERE t1.id
NOT IN
(
SELECT f.id
FROM (
SELECT id, name, MIN(net_price) as minprice
FROM offers
WHERE
supplier_id = (SELECT id FROM suppliers WHERE name = 'somename')
group BY name
)
AS x inner join (SELECT * FROM offers) AS f ON f.id = x.id
)
AND
t1.supplier_id = (SELECT id FROM suppliers WHERE name = 'somename');
Just add id to subquery select and put it on inner join f.id = x.id

Insert value into subquery

I'm trying to insert the value '1' into column 'isTransfer' of every result of an subquery, but it's not working. This is the query where I select the rows:
select r.*
from players r
inner join (
select name, rating, max(id) id
from players group by name, rating
having count(distinct club) > 1
)
q on r.name = q.name and r.rating = q.rating and r.id = q.id
This is what I'm trying to do:
INSERT INTO 'isTransfer' VALUES '1' WHERE
(select r.*
from players r
inner join (
select name, rating, max(id) id
from players group by name, rating
having count(distinct club) > 1
)
q on r.name = q.name and r.rating = q.rating and r.id = q.id)
For this task, you need to do an UPDATE query. Also, you cannot use the WHERE clause like that, you will get an error. Instead, change the where clause to look where the primary key is returned by the subquery. It would look something like this:
UPDATE myTable
SET isTransfer = 1
WHERE primaryKey IN [mySubquery];
You need to make sure that the only column in your SELECT of the subquery is the primary key, otherwise you will get an invalid operand count error.
In regards to your query in the comments, the JOIN is not necessary. Instead, just get the distinct id values from the subquery like this:
SELECT DISTINCT id
FROM(
SELECT name, rating, MAX(id) AS id
FROM players
GROUP BY name, rating
HAVING COUNT(DISTINCT club) > 1) q
Then, but that query as your IN operand.
Assuming the id is unique in the players table:
update players r inner join
(select name, rating, max(id) as id
from players p
group by name, rating
having count(distinct club) > 1
) nr
on r.id = nr.id
set isTransfer = 1;

can we have a query of "10 posts from every category in one request"?

We have a list of posts that belong a category.
can we have a query of "10 posts from every category in one request" ?
Or
We have to query 10 posts for every category separately ?
thx
A fudge involving using GROUP_CONCAT to put all the post ids for a category together (you can add an order clause to this if you want), then substring_index to get the first 10 posts.
This is then joined back to the original table using FIND_IN_SET
SELECT a.*
FROM some_table a
INNER JOIN
(
SELECT category_id, SUBSTRING_INDEX(GROUP_CONCAT(post_id), ',', 10) AS posts
FROM some_table
GROUP BY catgegory_id
) sub0
ON a.category_id = sub0.category_id
AND FIND_IN_SET(a.post_id, sub0.posts)
Or using variables:-
SELECT a.*
FROM some_table a
INNER JOIN
(
SELECT category_id, post_id, #cnt:=IF(#category_id=category_id, #cnt + 1, 1) AS cnt, #category_id:=category_id
FROM
(
SELECT category_id, post_id
FROM some_table
ORDER BY category_id, post_id
) sub0
CROSS JOIN (SELECT #cnt:=0, #category_id:=0) sub1
) sub2
ON a.category_id = sub2.category_id
AND a.post_id = sub2.post_id
AND cnt <= 10
This pseudo code should point you in the right direction.
SELECT DISTINCT CATEGORY FROM T AS T1
CROSS JOIN (SELECT * FROM T WHERE T.CATEGORY = T1.CATEGORY ORDER BY CATEGORY DESC LIMIT 10)