MySQL count number of times a result appears after grouping - mysql

I have a very similar problem to this one:
Count unique occurrences per each distinct variable in MySQL but with a twist.
I'm working with a select statement that shows results much like what the above-mentioned question does.
If I boil down my statement into a simple form for this question my code looks like this:
SELECT
salesman,
brand
FROM
sales
WHERE
sales.date=something
GROUP BY salesman, brand
Resulting in an example output like this:
salesman brand
____ _______
Mark aaa
Mark bbb
Mark ccc
Mark ddd
Jane aaa
Jane bbb
Cody aaa
Without the GROUP BY part the results might look like this:
salesman brand
____ _______
Mark ddd
Jane bbb
Mark aaa
Cody aaa
Mark ddd
Jane aaa
Mark aaa
Jane aaa
Mark ccc
Mark bbb
The twist I have is that I want to count the number of times each brand appears after the grouping and output it in the same table of results.
EG:
salesman brand brand_count
____ _______ _____
Mark aaa 3
Mark bbb 2
Mark ccc 1
Mark ddd 1
Jane aaa 3
Jane bbb 2
Cody aaa 3
I've tried adding count(*) to the SELECT but that only returns the number 2 for salesman Mark with brand aaa and 1 for Cody, which isn't what I'm after.
I want to show for each brand the number of times it appeared in the results.
So brand aaa for example shows 3 times.
I suspect there might be a subquery needed though I'm not sure how it would work.
Any suggestions would be greatly appreciated.
EDIT:
Original MySQL code below in case it helps
select
ARM.SALESMAN AS 'SalesmanNumber',
INM.BRAND AS 'Brand'
from
ARMASTER ARM
LEFT JOIN ARTRAN ART ON ARM.NUMBER = ART.CUST_NO
LEFT JOIN INTRAN INTR ON ART.REF = INTR.REF
LEFT JOIN ARSALECD SALESMAN ON ARM.SALESMAN = SALESMAN.CODE
LEFT JOIN INMASTER INM ON INTR.STOCK_CODE = INM.CODE
where
ARM.AREA = 01
AND ARM.CUSTTYPE <> '99'
AND ARM.SALESMAN NOT IN (24,48,49,50,51,52,71,72,74,90)
AND (
(YEAR(INTR.DATE) = YEAR(#mth) AND MONTH(INTR.DATE) = MONTH(#mth))
OR (YEAR(DATE_ADD(#mth, INTERVAL -1 MONTH)) AND MONTH(INTR.DATE) = MONTH(DATE_ADD(#mth, INTERVAL -1 MONTH)))
OR (YEAR(DATE_ADD(#mth, INTERVAL -2 MONTH)) AND MONTH(INTR.DATE) = MONTH(DATE_ADD(#mth, INTERVAL -2 MONTH)))
)
group by Brand , SalesmanNumber;
I tried making the select part of the statement look like this per Robo suggestion:
ARM.SALESMAN AS 'SalesmanNumber',
INM.BRAND AS 'Brand',
(
SELECT
count(*)
FROM
INMASTER AS s
WHERE
s.BRAND=INMASTER.BRAND
) AS brand_count
But get this error
Error Code: 1054. Unknown column 'INMASTER.BRAND' in 'where clause'
Also, I'm working with an old database version: MySQL 5.1.60

On an older MySQL version you can use:
select s.salesman,s.brand,brand_count
from sales s
inner join (select brand,count(brand) as brand_count
from ( select salesman,brand
from sales
group by salesman,brand
) as tbl
group by brand
) as x on x.brand=s.brand
group by salesman,brand,brand_count
order by s.salesman ;
https://dbfiddle.uk/EevII2mZ
Group by the result , in an outer query count the brand and then use that as a subquery to join with the primary same table

You need to use a subquery:
SELECT
salesman,
brand,
(
SELECT
count(*)
FROM
sales AS s
WHERE
s.brand=sales.brand
) AS brand_count
FROM
sales
WHERE
sales.date=something
GROUP BY salesman, brand

On MySQL v8+, you can use COUNT() OVER () function.
Create table & data example:
CREATE TABLE sales(
salesman VARCHAR(255),
brand VARCHAR(255),
date DATE);
INSERT INTO sales VALUES
('Mark','ddd','2022-10-06'),
('Jane','bbb','2022-10-06'),
('Mark','aaa','2022-10-06'),
('Cody','aaa','2022-10-06'),
('Mark','ddd','2022-10-06'),
('Jane','aaa','2022-10-06'),
('Mark','aaa','2022-10-06'),
('Jane','aaa','2022-10-06'),
('Mark','ccc','2022-10-06'),
('Mark','bbb','2022-10-06');
Query:
SELECT
salesman,
brand,
COUNT(brand) OVER (PARTITION BY Brand) AS brand_count
FROM
sales
WHERE date='2022-10-06'
GROUP BY salesman, brand
ORDER BY salesman DESC, brand
Results:
salesman
brand
brand_count
Mark
aaa
3
Mark
bbb
2
Mark
ccc
1
Mark
ddd
1
Jane
aaa
3
Jane
bbb
2
Cody
aaa
3
Demo fiddle
For older MySQL version:
SELECT t1.salesman, t1.brand, brand_count
FROM sales t1
JOIN
/*this part of the query is just to get the brand_count*/
(SELECT brand, COUNT(*) AS brand_count
FROM
(SELECT salesman, brand
FROM sales
WHERE date='2022-10-06'
GROUP BY salesman, brand) t
GROUP BY brand) t2
/*this part of the query is just to get the brand_count*/
ON t1.brand=t2.brand
WHERE t1.date='2022-10-06'
GROUP BY t1.salesman, t1.brand
ORDER BY t1.salesman DESC, t1.brand;
Demo fiddle

Related

How to select from Table by group

I have table like this:
idjob category customer
1560 001 1
1560 0010 1
1560 002 1
1562 001 2
1562 0010 2
1563 001 2
1563 002 3
1563 0010 3
1563 004 3
One customer can have more idjobs.
Every single jobs contain a group of categories.
I would like to select the number of customer that have two or more specifics category by its jobs.
Probably it is a simple query.
How can i do that?
Thank you
You could count the number of different idjob per customer:
SELECT customer, GROUP_CONCAT(idjob) AS jobs
FROM mytable
GROUP BY customer
HAVING COUNT(DISTINCT idjob) > 1
You can get the customers meeting the condition using:
select customer
from t
group by customer
having min(category) <> max(category);
To get the number, use a subquery:
select count(*)
from (select customer
from t
group by customer
having min(category) <> max(category)
) c;
Note that "2" is a special case. It can be handled by comparing the max() and min(). The more general solution would use count(distinct category) >= 2. However, count(distinct) is more resource intensive than simpler aggregation functions.
EDIT:
Perhaps I misread the original question.
If you want customers with a particular set of categories, you can still use GROUP BY and HAVING:
select customer
from t
where category in (. . .)
group by customer
having count(*) = <n>;
Here . . . is the list of categories you want. <n> is the number of categories in that list.
If you can have duplicate customer/category pairs, then use this having:
having count(distinct category) = <n>

Having the number of line having a specifc ID without group by SQL

I have a 'billing' table which represent all instances of billings from my subscribers. A subscriber can have multiple billings.
I have a simple SQL request which is :
SELECT count(billing_id),subscriber_id
FROM billing
group by subscriber_id
As a result I have a list of all my subscribers with the number of billings they've made.
I want to have a list of all the billings no grouped by subscribers, but I want the result of the previous request appearing in each lines.
Example:
Result of my previous request:
sub_id nb_billings
1 3
2 2
What I want :
sub_id nb_billings
1 3
1 3
1 3
2 2
2 2
Thanks
I'd do it like this;
SELECT
b.subscriber_id
,a.billing_count
FROM billing b
JOIN (SELECT subscriber_id, count(billing_id) billing_count FROM billing GROUP BY subscriber_id) a
ON b.subscriber_id = a.subscriber_id
The subquery works out the count of billing_id by subscriber, this is then joined to all rows of your original table (using subscriber_id). This should give the result you're after.
You can use a subquery to do that:
SELECT
(SELECT count(t2.billing_id) FROM billing t2 WHERE t2.subscriber_id = t1.subscriber_id),
t1.subscriber_id
FROM billing t1
I guess this should suffice :
SELECT s.subscriber_id,
s.billing_id,
s.TotalCount
FROM (
SELECT subscriber_id,
billing_id,
COUNT(billing_id) AS TotalCount
FROM BILLING
GROUP BY subscriber_id,
billing_id
) s
GROUP BY s.subscriber_id,
s.TotalCount,
s.billing_id
ORDER BY s.subscriber_id
This should give you the result as follows :
subscriber_id billing_id TotalCount
1 10a 2
1 10b 2
1 10c 1
2 10a 1
2 10b 1
2 10c 3
2 10d 1
You can see this here -> http://rextester.com/AVVS23801
Hope this helps!!
select subscriber_id,count(billing_id)over(partition by subscriber_id)
from billing
will do just that.

Combine query for sum of two tables with date

I have two tables like following
challenge_table
Challenger chdate
----------------------
abc 11-02-2012
aaa 12-02-2012
ccc 12-02-2012
bbb 13-02-2012
ddd 14-02-2012
init_table
Initiateid indate
----------------------
a1 11-02-2012
a2 11-02-2012
a3 12-02-2012
a4 13-02-2012
a5 13-02-2012
I need a result like this
challengecount initcount curdate
-----------------------------------
1 2 11-02-2012
2 1 12-02-2012
1 2 13-02-2012
1 0 14-02-2012
i tried a query like this
SELECT COUNT(*) challengecount, chdate caldate FROM challenge_table
UNION ALL
SELECT COUNT(*) Initiatecount, indate caldate FROM init_table
But it doesn't work for me.
Since MySQL does not support a FULL OUTER JOIN, you need to combine the 2 tables with a UNION.
Then group by the date and count the values of the 2 tables
select caldate, count(distinct Challenger), count(distinct Initiateid)
from
(
SELECT Challenger, null as Initiateid, chdate as caldate FROM challenge_table
UNION ALL
SELECT null, Initiateid, indate FROM init_table
) tmp
group by caldate

Query orders table and get most recent record for each customer

I have a table of orders. Customers can appear multiple times. The orderID column is an auto increment. I need to run a query to get the most recent order for each customer BUT I need to get the orderID, orderDate and orderProduct of their latest order.
customer orderID orderDate orderProduct
1 1 2015-01-01 shoes
1 2 2015-02-01 food
1 3 2015-03-01 drinks
2 4 2015-01-01 water
2 5 2015-04-01 beer
3 6 2015-01-01 pizza
3 7 2015-07-01 pasta
I had hoped to use:
select orders.*, max(orderDate) as latestOrder from orders group by customer
But this doesn't seem to give me what I need.
The results I am looking for would be:
customer orderID orderDate orderProduct
1 3 2015-03-01 drinks
2 5 2015-04-01 beer
3 7 2015-07-01 pasta
use some kind of self-join here
select t1.* from orders t1
inner join (
select customer, max(orderDate) as latestOrder from orders
group by customer
) t2
where t1.customer = t2.customer AND t1.orderDate = t2.latestOrder
WITH CTE AS(
SELECT customer,orderID,orderDate,orderProduct,
ROW_NUMBER()OVER(PARTITION BY customer ORDER BY orderID desc)
FROM tab
)
select * from tab where orderid in (
select max(orderid) as maxorder from cte group by customer)
This should work with any RDBMS that supports CTEs. Heres a demo

Need help on using COUNT and SUM together in MySQL

I have got 2 tables: Institute & Course
Institute
---------
i_id i_name i_city
------ -------- --------
1 Name 1 London
2 Name 2 Manchester
3 Name 3 London
Course
-------
c_id i_id stream
------ ------- --------
1 1 Engineering
2 1 Engineering
3 2 Engineering
4 3 Engineering
Now I am trying to achieve 3 things:
a) Number of Institutes per city offering Engineering courses.
b) Total (distinct) Number of Institutes offering Engineering courses.
I started writing below query to achieve this:
SELECT institute.i_city,
COUNT( DISTINCT institute.i_id ) AS institute_count_per_city
FROM institute, course
WHERE institute.i_id = course.i_id
AND course.stream = 'Engineering'
GROUP BY institute.i_city
I got below result:
i_city institute_count_per_city
------- -------------------------
London 2
Manchester 1
Now I have achieved the count of institutes per city.
I can't figure how can I get the total number of institutes in same query which in the above example will be 3 (2+1)
I would really appreciate the help.
Use ROLLUP:
SELECT institute.i_city,
COUNT( DISTINCT institute.i_id ) AS institute_count_per_city
FROM institute, course
WHERE institute.i_id = course.i_id
AND course.stream = 'Engineering'
GROUP BY institute.i_city WITH ROLLUP
It will add additional row with SUM of your aggregated values.
Update
GrandTotal version:
SELECT IFNULL(institute.i_city, 'GrandTotal'),
COUNT( DISTINCT institute.i_id ) AS institute_count_per_city
FROM institute, course
WHERE institute.i_id = course.i_id
AND course.stream = 'Engineering'
GROUP BY institute.i_city WITH ROLLUP
Would a union query help?
your existing query
union
select 'total' I_city, count(*) institute_count_per_city
FROM institute, course
WHERE institute.i_id = course.i_id
AND course.stream = 'Engineering'
GROUP BY 'total'