MySQL "Distinct" join super slow - mysql

I have the following query which gives me the right results. But it's super slow.
What makes it slow is the
AND a.id IN (SELECT id FROM st_address GROUP BY element_id)
part. The query should show from which countries we get how many orders.
A person can have multiple addresses, but in this case, we only only want one.
Cause otherwise it will count the order multiple times. Maybe there is a better way to achieve this? A distinct join on the person or something?
SELECT cou.title_en, COUNT(co.id), SUM(co.price) AS amount
FROM customer_order co
JOIN st_person p ON (co.person_id = p.id)
JOIN st_address a ON (co.person_id = a.element_id AND a.element_type_id = 1)
JOIN st_country cou ON (a.country_id = cou.id)
WHERE order_status_id != 7 AND a.id IN (SELECT id FROM st_address GROUP BY element_id)
GROUP BY cou.id

Have you tried to replace the IN with an EXISTS?
AND EXISTS (SELECT 1 FROM st_address b WHERE a.id = b.id)
The EXISTS part should stop the subquery as soon as the first row matching the condition is found. I have read conflicting comments on if this is actually happening though so you might throw a limit 1 in there to see if you get any gain.

I found a faster solution. The trick is a join with a sub query:
JOIN (SELECT element_id, country_id, id FROM st_address WHERE element_type_id = 1 GROUP BY
This is the complete query:
SELECT cou.title_en, COUNT(o.id), SUM(o.price) AS amount
FROM customer_order o
JOIN (SELECT element_id, country_id, id FROM st_address WHERE element_type_id = 1 GROUP BY element_id) AS a ON (o.person_id = a.element_id)
JOIN st_country cou ON (a.country_id = cou.id)
WHERE o.order_status_id != 7
GROUP BY cou.id

Related

Get total count and comments with posts

I want to get the total likes and total count of the every post in a single query with the help of joins.
I am using this query. but the result is wrong
SELECT blog.id, count(blog_comments.id) as likes , count(blog_likes.id) as comments
FROM blog LEFT JOIN
blog_comments
ON blog.id = blog_comments.blog_id LEFT JOIN
blog_likes
ON blog.id = blog_likes.blog_id
GROUP BY blog.id
Please check the image for table structure:
Your problem is that you are aggregating along two dimensions at the same time. The produces a Cartesian product -- a row with each like pairs with each comment, for a total of l * c rows.
The simplest way to fix this is to use the DISTINCT keyword:
SELECT b.id, count(DISTINCT bl.id) as likes , count(DISTINCT bc.id) as comments
FROM blog b LEFT JOIN
blog_comments bc
ON b.id = bc.blog_id LEFT JOIN
blog_likes
ON b.id = bl.blog_id
GROUP BY b.id;
If you have posts that have lots of likes and lots of comments, this is not recommended, because it creates a Cartesian product of the two.
There are several solutions for this, but I would recommend correlated subqueries:
select b.id,
(select count(*) from blog_likes bl where bl.blog_id = b.id) as likes,
(select count(*) from blog_comments bc where bc.blog_id = b.id) as comments
from blogs b;
This can take advantage of indexes on blog_likes(blog_id) and blog_comments(blog_id).
This is according to my table it will help you...
SELECT people.pe_name, COUNT(distinct orders.ord_id) AS num_orders, COUNT(items.item_id) AS num_items FROM people INNER JOIN orders ON orders.pe_id = people.pe_id INNER JOIN items ON items.ord_id = orders.ord_id GROUP BY people.pe_id;

MySQL - Group orders count by clients numbers

I want to group order's count to show how many clients have that number of orders.
I have come up with:
select count(*) as quantidade_pedidos, clientes.id
from pedidos
inner join clientes
on pedidos.cliente_id = clientes.id
where pedidos.aprovado = 1
group by quantidade_pedidos
but I just can't group by 'quantidade_pedidos' anyway.
Is there any way to group by a temporary column? Another way of doing this? show how many clients (number) have that number of orders placed?
Example
8 orders placed -> 3 clients have 8 orders placed
etc
Your original query is wrong. You need to group by clientes.id:
select count(*) as quantidade_pedidos, c.id
from pedidos p inner join
clientes c
on p.cliente_id = c.id
where p.aprovado = 1
group by c.id;
In an aggregation query, the unaggregated columns go in the group by, not the aggregated ones.
Also note that table aliases make the query easier to write and to read.
As for the question in the first line, use a subquery:
select quantidade_pedidos, count(*)
from (select count(*) as quantidade_pedidos, c.id
from pedidos p inner join
clientes c
on p.cliente_id = c.id
where p.aprovado = 1
group by c.id
) x
group by quantidade_pedidos;
But given that the query in the question doesn't work, I'm not sure this is what you really want to do.

Sorting results from joins

While running this query:
SELECT
a.id,
pub.name AS publisher_name,
pc.name AS placement_name,
b.name AS banner_name,
a.lead_id,
a.partner_id,
a.type,
l.status,
s.correctness,
a.landing_page,
t.name AS tracker_name,
a.date_view,
a.date_action
FROM actions AS a
LEFT JOIN publishers AS pub ON a.publisher_id = pub.id
LEFT JOIN placements AS pc ON pc.publisher_id = pub.id
LEFT JOIN banners AS b ON b.campaign_id = a.campaign_id
LEFT JOIN leads l ON
l.lead_id = a.lead_id
AND l.created = (
SELECT MAX(created) from leads l2 where l2.lead_id = l.lead_id
)
LEFT JOIN statuses AS s ON l.status = s.status
LEFT JOIN trackers AS t ON t.id = a.tracker_id
LIMIT 10
I am able to sort by every column from actions table. However when I try to for example ORDER BY b.name (from banners table, joined on actions.banner_id) or ORDER BY l.lead_id (joined from leads on more complex condition as seen above) MySQL is running query for a loooong time (most tables have tens of thousands records). Is it possible, performance-wise, to sort by joined columns?
You should rewrite the query with a inner join on the table where the column you want to sort on is.
For example, if you sort on actions.banner_id
SELECT ...
FROM actions AS a
JOIN banners AS b ON b.campaign_id = a.campaign_id
LEFT JOIN *rest of the query*
You will get the same results unless there is not enough banners that can be joined to action to produce a total of 10 rows.
I'm guessing it's not the case otherwise you wouldn't be sorting on banner_id.
You could first filter (order by, where, etc.) your records in a subquery and then join the result with the rest of the tables.

MySQL COUNT from 2 tables

I'm drawing a huge blank on something I'm sure I've done before, and is probably simple.
Alas, I'm going to ask for assistance anyways.
I have 2 tables:
tbl_admins_groups
tbl_admins
I'm pulling a query on the just the admin group table:
SELECT groupid, groupname, groupdesc FROM tbl_admins_groups
And now I'd like to add another column that counts the number of admin records associated to that groupid.
Here's my attempt:
SELECT g.groupid, g.groupname, g.groupdesc, COUNT(a.adminid) AS `admincount`
FROM `tbl_admins_groups` g, `tbl_admins` a
WHERE g.groupid = a.groupid
AND a.adminstatus = 1
GROUP BY g.groupid
For some reason I'm getting just one result back.
Is my GROUP BY incorrect?
You can get their COUNT inside subquery and join it with tbl_admins_groups
SELECT g.groupid, g.groupname, g.groupdesc,
a.totalCount
FROM tbl_admins_groups g
LEFT JOIN
(
SELECT groupid, COUNT(*) totalCount
FROM tbl_admins
WHERE adminstatus = 1
GROUP BY groupid
) a
ON g.groupid = a.groupid

Count on joined table causes return of 1 row

I've got query like:
SELECT
b.title,
b.url,
b.`date`,
b.gallery,
count(c.id) as comments_count,
a.name,
b.content,
b.comments,
LEFT(b.content, LOCATE('<page>', b.content)-1) as content_short
FROM blog b
LEFT JOIN blog_comments c ON
(b.id = c.note AND c.approved = 1)
LEFT JOIN administrators a ON
(b.aid = a.id)
WHERE
b.`date` < now() AND
b.active = 1
ORDER BY b.`date` DESC;
Now, when I remove count(c.id) as comments_count,, I've got 2 rows returned. When it's present, there's only 1 row returned.
Is there some way to fix ot or I simply have to change
count(c.id) as comments_count, to (select count(id) ascomments_countfrom blog_comments where note = b.id) as comments_count,?
Count(*) is an aggregated function, so it will apply in a group.
That means that when you count on groups, it will apply the function on every group.
The groups are formed when you use Group By, in this case, you're not using, so MySQL consider that ALL select (your joins) is ONLY 1 GROUP.
So, applies the count on the unique group and returning the count of rows.
you should add a Group by by the field you want
An example is here