MYSQL GROUP BY LEFT JOIN and COUNT - mysql

I am having a problem grouping and counting items in a MYSQL database with JOIN clause
My two tables are as follows
users table
id | surname | othernames
1 | Doe | John
2 | Doe | Jane
3 | Doe | Mary
subscriptions table
id | user_id | parent_subscription_id
1 | 1 | Null
2 | 2 | 1
3 | 3 | 1
4 | 4 | 2
5 | 5 | 3
6 | 6 | 3
I need to be able to produce a list as follows
Name | Referrals
John Doe | 2
Jane Doe | 1
Mary Doe | 2
In other words,it Is the user in users table with the users.id which matches subscriptions.user_id that has the subscription with subscriptions.id which is a parent subscription to another subscription. That means, if your subscription is referenced by another subscription as its own parent_subscription_id, then that new subscription becomes your referral.
I have tried the following query and it is not giving me the expected results
SELECT users.surname, users.othernames,count('s.parent_subscription_id') as referrals
FROM users
LEFT JOIN subscriptions s ON s.user_id=users.id
group BY parent_subscription_id
I have checked some other questions on SO but I have not been able to find any that solves this type of issue
Thank you

I think that the logic you want is:
select u.surname, u.othernames, count(s.parent_subscription_id) referrals
from subscriptions s
left join subscriptions p on p.id = s.parent_subscription_id
inner join users u on u.id = coalesce(p.user_id, s.user_id)
group by u.id, u.surname, u.othernames
Demo on DB Fiddle:
surname | othernames | referrals
:------ | :--------- | --------:
Doe | John | 2
Doe | Jane | 1
Doe | Mary | 2

You ca use join between users table and select calculated count as:
SELECT
-- Get all users
users.surname,
users.othernames,
IFNULL(reff.cnt, 0) as referrals -- Preset 0 for users have not referrals in joined table
FROM users
-- Join calculation result
LEFT JOIN (
-- Calculate count by user
SELECT parent_subscription_id, COUNT(*) AS cnt
FROM subscriptions
GROUP BY subscriptions.parent_subscription_id
) reff on reff.parent_subscription_id = users.id;

Change group by fields with users.surname, users.othernames
SELECT users.surname, users.othernames,count(s.parent_subscription_id) as referrals
FROM users
LEFT JOIN subscriptions s ON s.user_id=users.id
group BY users.surname, users.othernames

you need to group by id of users table because you need get count for each user and here is your main table is users. try like this.
SELECT users.surname, users.othernames, count('s.parent_subscription_id') as referrals
FROM users
LEFT JOIN subscriptions s ON s.user_id = users.id
group BY users.id

This query eventually gave me the result I have been looking for
SELECT u.surname,u.othernames,s1.id,s1.parent_subscription_id,
s1.refcode, IFNULL(count(s2.parent_subscription_id),0) as referrals
FROM `subscriptions` s1 left join subscriptions s2
on s1.id=s2.parent_subscription_id
LEFT JOIN users u ON u.id=s1.user_id
GROUP by s1.id
Thank you all for your guidance and support on this. I deeply appreciate it

Related

Mysql join tables without repeating rows which belong to same row

I've been trying to figure this out for hours. But with no luck.
This works perfectly, but the problem i got with these. For e.g if same report has more than 1 comment, then this will create new row instead of unite the comments with same row with the report.
How it's now:
{"text":"My first report","comment":"Great Report","display_name":"Xavier"},
{"text":"My First report","comment":"Do you call this a report?","display_name":"Logan"}
How i would like it to be:
{"text":"My first report","comments":[{comment: "Great Report","display_name":"Xavier"}, {comment: "Do you call this a report?","display_name":"Logan"}],
Current Setup
Report
ID | User_ID | TEXT |
15 3 My first report
Users
ID | DISPLAY_NAME |
1 Xavier
2 Logan
3 Cyclops
Report_Comments
ID | User_ID | Report_ID | TEXT as comment |
3 1 15 Great Report
4 2 15 Bad Report
How it should be:
Report_Comments
ID | User_ID | Report_ID | TEXT as comment |
3 1, 2 15 Great Report, Bad Report
SELECT report.text,
report_comments.text AS comment,
users.display_name
FROM report
LEFT JOIN users
ON users.id = report.user_id
LEFT JOIN report_comments
ON report_comments.report_id = report.id
WHERE report.user_id = :userId
You can do it if you group by report and use GROUP_CONCAT() for user ids and names and comment texts:
SELECT r.text,
GROUP_CONCAT(c.user_id ORDER BY c.ID) AS User_ID,
GROUP_CONCAT(u.display_name ORDER BY c.ID) AS User_Name,
r.id,
GROUP_CONCAT(c.text) AS comment
FROM report r
LEFT JOIN report_comments c ON c.report_id = r.id
LEFT JOIN users u ON u.id = c.user_id
-- WHERE report.user_id = :userId
GROUP BY r.id, r.text
See the demo.
Results:
> text | User_ID | User_Name | id | comment
> :-------------- | :------ | :----------- | :- | :----------------------
> My first report | 1,2 | Xavier,Logan | 15 | Bad Report,Great Report

MySQL count function with a join?

I've two tables.
User(id,name)
Finance(id,item_id,amount,user_id)
My use case is
users are the employees (sales guys) of the organization.
When they sell an item finance table get updated with a new record of that sold item's serial id.
I want to get the user names along with the total value of the sales they made.
User
id | name
1 | Dinesh
2 | Pathum
3 | Naveed
Finance
id | item_id | amount | user_id
1 | 1 | 2000 | 1
2 | 2 | 2000 | 1
3 | 3 | 1000 | 3
4 | 4 | 500 | 3
Expected output
Dinesh 4000
Pathum 0
Naveed 1500
How do I achieve this using MySQL?
The query is like the following:
SELECT u.name as 'Agent Name',
if(sum(f.amount) IS NULL, 0,sum(f.amount)) as Total,
f.createdAt
FROM users u LEFT JOIN finance f
ON u.id = f.user_id
GROUP BY u.id, u.name, f.createdAt
ORDER BY f.createdAt DESC
Here is a working SQL Fiddle.
Join em, group em, sum em.
SELECT usr.name AS UserName, COALESCE(SUM(fin.amount),0) AS TotalAmount
FROM `User` usr
LEFT JOIN `Finance` fin ON fin.user_id = usr.id
GROUP BY usr.id, usr.name
ORDER BY usr.id;
Test on db<>fiddle here
Another way:
SELECT Name,SUM(IFNULL(amount,0)) AS "Total" FROM (SELECT Name,amount FROM user LEFT JOIN finance ON user.id=finance.user_id) a GROUP BY Name;

MYSQL - Group Contact rows with records NOT IN

My case looks simple but i'm messing around with this..
I have 4 tables: User, Macros, Categories, and another one that relate users with categories. One Macro have many Categories.
What i need, is a query that based on the Macro, get the users and the Categories where user is NOT IN.
Example: I have a macro named VEICULES, with categories CAR,TRUCK and Motorcycle. User José is on category CAR and User Julio on category CAR and TRUCK, so my query should return:
José | TRUCK,Motorcycle
Julio | Motorcycle
Tables:
prd_users
id | name | Email
---------------------------
1 | José | jose#email.com
2 | Júlio | julio#email.com
3 | André | andre#email.com
cat_macros
macro_id | macro_name
-----------------------
1 | Veicules |
cat_categories
category_id | category_name | macro_id
---------------------------------------
1 | Cars | 1
2 | Trucks | 1
3 | Motorcycles | 1
prd_tr_rabbit_catg
id | category_id | tasker_user_id
---------------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 2
I'm stucked on just getting the categories where the user already is ..
SELECT prd_users.id, prd_users.name,
prd_users.email,cat_macros.macro_name as macro,
GROUP_CONCAT(cat_categories.category_name SEPARATOR ', ') as in_categories
FROM prd_users
INNER JOIN prd_tr_rabbit_catg ON prd_tr_rabbit_catg.tasker_user_id = prd_users.id
INNER JOIN cat_categories ON cat_categories.category_id = prd_tr_rabbit_catg.category_id
INNER JOIN cat_macros ON cat_macros.macro_id = cat_categories.macro_id
WHERE cat_macros.macro_id = '45'
GROUP BY prd_users.id;
To solve this problem it's necessary to create a list of all users joined with all categories for the given macro category. This can be done with a CROSS JOIN:
SELECT *
FROM prd_users u
CROSS JOIN (SELECT m.macro_id, m.macro_name, c.category_name, c.category_id
FROM cat_macros m
JOIN cat_categories c ON c.macro_id = m.macro_id) c
This can then be LEFT JOINed to the prd_tr_rabbit_catg table and by selecting those rows where there is no matching entry in the prd_tr_rabbit_catg table, we can find the users who don't have an entry for the given category:
SELECT c.macro_name, u.id AS user_id, u.name, u.Email, GROUP_CONCAT(c.category_name) AS missing_cats
FROM prd_users u
CROSS JOIN (SELECT m.macro_id, m.macro_name, c.category_name, c.category_id
FROM cat_macros m
JOIN cat_categories c ON c.macro_id = m.macro_id) c
LEFT JOIN prd_tr_rabbit_catg x ON x.tasker_user_id = u.id AND x.category_id = c.category_id
WHERE x.id IS NULL
AND c.macro_id = 1
GROUP BY c.macro_name, u.id
For your sample data, this gives:
macro_name user_id name Email missing_cats
Veicules 1 José jose#email.com Motorcycles,Trucks
Veicules 2 Júlio julio#email.com Motorcycles
Veicules 3 André andre#email.com Cars,Motorcycles,Trucks
Update
To exclude users who don't have any of the categories, add a HAVING clause:
HAVING COUNT(*) < (SELECT COUNT(*) FROM cat_categories WHERE macro_id = 1)
Demo on SQLFiddle

Return Number Of Times An ID Is Repeated

so I have two tables:
orders
order_id | user_id
1 | 1
2 | 1
3 | 1
4 | 2
5 | 2
users
user_id | name
1 | John
2 | Mike
I want to return the id, name of the client and how many orders he has placed. Something like this:
user_id | name | num_orders
1 | John | 3
2 | Mike | 2
I tried to do the following query but it only returns the first user's name and the total amount of orders. This is the query I have:
SELECT
users.user_id,
users.name,
COUNT(orders.order_id) AS num_orders
FROM users
LEFT JOIN orders
ON users.user_id = orders.user_id
ORDER BY users.user_id DESC
Any help is greatly appreciated! :)
You are missing a GROUP BY statement. If you add in at the end
GROUP BY users.user_id
it should rectify your issues.
For more help on SQL statements try http://www.dofactory.com/sql/tutorial
What you are looking for is a GROUP BY clause. It is used with aggregate functions (COUNT, MAX, MIN, SUM, AVG) to group the results by one or more columns. Here is how it works.
SELECT
users.name,
users.user_id,
count(users.user_id) as total
FROM users
LEFT JOIN orders ON users.user_id = orders.user_id
GROUP BY users.user_id
ORDER BY users.user_id DESC
And the results:
username |user_id | total
John | 3 | 3
Mary | 2 | 5
Carl | 1 | 1
...

SQL Count Rows From Multiple tables

Lets say i have 2 tables
Companies
company_id
name
Users
id
company_id
name
each company has multiple users assign to it... which is referenced in the company_id field from each record in the users table
HOW can i get a record showing the (company_id), (company_name) and (number or users)
for eg:
id# 1234 | name# Microsoft | n of users# 2000
I dont know how to make this query, i know i have to use the function COUNT() but i dont know how
If you want to get all companies even if they don't have any users yet use OUTER JOIN
SELECT c.company_id, c.name company_name, COUNT(u.id) no_of_users
FROM companies c LEFT JOIN users u
ON c.company_id = u.company_id
GROUP BY c.company_id, c.name
Sample output:
| COMPANY_ID | COMPANY_NAME | NO_OF_USERS |
|------------|--------------|-------------|
| 1 | Company1 | 3 |
| 2 | Company2 | 2 |
| 3 | Company3 | 0 |
Here is SQLFiddle demo
this will be the query
select Companies.company_id,Companies.name,count(Users .id) from Companies,Users where Companies=company_id and Users =company_id group by company_id
Try :
SELECT companies.company_id,companies.company_name,COUNT(users.id)
FROM companies, users
WHERE companies.id = users.company_id
group by companies.id