SQL Count Rows From Multiple tables - mysql

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

Related

MYSQL GROUP BY LEFT JOIN and COUNT

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

MySQL many-to-many JOIN returning duplicates

I have two three tables. users, jobs and users_jobs. One user can have many jobs and one job can have many users.
Here is my users table:
+----+------+--------+
| ID | Name | gender |
+----+------+--------+
| 1 | Bob | male |
| 2 | Sara | female |
+----+------+--------+
my jobs table:
+----+----------+
| id | job_id |
+----+----------+
| 1 | Engineer |
| 2 | Plumber |
| 3 | Doctor |
+----+----------+
users_jobs table:
+---------+--------+
| user_id | job_id |
+---------+--------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
+---------+--------+
As an example, i want to select all males and check if they have at least 1 job and then return their info. If they have no jobs, then don't select/return that user. This is my query:
SELECT * FROM users
INNER JOIN users_jobs
ON users_jobs.user_id = users.id
WHERE users.gender = 'male'
But it returns Bob's info 3 times since he has 3 jobs. I don't want duplicates, how can I get rid of duplicates without using DISTINCT or GROUP BY since performance is very important here.
Thank you!
MySQL allows you to do one a little odd thing, you can select more columns than what's in the GROUP BY clause and aggregate functions (this is not allowed in most other SQL engines). While this sometimes can produce unexpected results, it can work if you don't select data which can appear in multiple rows in the resulting query.
So, for your question - the query WILL return multiple rows for the same user, as some of them have many jobs (busy life, huh?). You generally can't get all their jobs in a single row, as each row is the user's data + their jobs - that's what we JOIN on. But that's not entirely true - you can use GROUP BY and GROUP_CONCAT() to concat all the other data into a single string. I wouldn't generally recommend it, but if its what you need...
SELECT u.Name, GROUP_CONCAT(j.job_id SEPARATOR ', ') as jobs
FROM users u
JOIN users_jobs uj
ON u.ID = uj.user_id
JOIN jobs j
ON j.id = uj.job_id
GROUP BY u.ID
This would return
Name | jobs
--------+-------------------------------
Bob | Engineer, Plumber, Doctor
Sara | Engineer
If you only want males, add in the where clause,
SELECT u.Name, GROUP_CONCAT(j.job_id SEPARATOR ', ') as jobs
FROM users u
JOIN users_jobs uj
ON u.ID = uj.user_id
JOIN jobs j
ON j.id = uj.job_id`
WHERE u.gender = 'male'
GROUP BY u.ID
See live fiddle at http://sqlfiddle.com/#!9/df0afe/2
For this it may will help you,
You can use "Limit" keyword to limit the amount of records fetched
"SELECT * FROM users
INNER JOIN users_jobs
ON users_jobs.user_id = users.id
WHERE users.gender = 'male'" limit 1;
May this will help you!
Thanks!
To follow on from the comments, for performance, it's necessary to use a distinct in your query, try:
SELECT DISTINCT Name FROM users
INNER JOIN users_jobs
ON users_jobs.user_id = users.id
WHERE users.gender = 'male'
If you're looking to get all the columns but keep the id's distinct you can use a GROUP BY, try:
SELECT * FROM users
INNER JOIN users_jobs
ON users_jobs.user_id = users.id
WHERE users.gender = 'male'
GROUP BY users.id
Although this will also effect performance, it depends on what you prioritize the most.

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;

SQL left join: how to return the newest from tableB and grouped by another field

I've been trying for two days, without luck.
I have the following simplified tables in my database:
customers:
| id | name |
| 1 | andrea |
| 2 | marco |
| 3 | giovanni |
access:
| id | name_id | date |
| 1 | 1 | 5000 |
| 2 | 1 | 4000 |
| 3 | 2 | 1500 |
| 4 | 2 | 3000 |
| 5 | 2 | 1000 |
| 6 | 3 | 6000 |
| 7 | 3 | 2000 |
I want to return all the names with their last access date.
At first I tried simply with
SELECT * FROM customers LEFT JOIN access ON customers.id =
access.name_id
But I got 7 rows instead of 3 as expected. So I understood I need to use GROUP BY statemet as the following:
SELECT * FROM customers LEFT JOIN access ON customers.id =
access.name_id GROUP BY customers.id
As far I know, GROUP BY combines using a random row. In fact I got unordered access dates with several tests.
Instead I need to group every customer id with its corresponding latest access! How this can be done?
You have to get the latest date from the access table with a group by on the the name_id, then join this result with the customer table. Here is the query:
select c.id, c.name, a.last_access_date from customers c left join
(select id, name_id, max(access_date) last_access_date from access group by name_id) a
on c.id=a.name_id;
Here is a DEMO on sqlfiddle.
I think this is what you'd like to achieve:
SELECT c.id, c.name, max(a.date) last_access
FROM customers c
LEFT JOIN access a ON c.id = a.name_id
GROUP BY c.id, c.name
The LEFT join will return all entries in table customers regardless if the join criteria (c.id = a.name_id) is satisfied. This means that you might get some NULL entries.
Example:
Simply add a new row in the customers table (id: 4, name: manuela). The output will have 4 rows and the newest row will be (id: 4, last_access: null)
I would do this using a correlated subquery in the ON clause:
SELECT a.*, c.*
FROM customers c LEFT JOIN
access a
ON c.id = a.name_id AND
a.DATE = (SELECT MAX(a2.date) FROM access a2 WHERE a2.name_id = a.name_id);
If this statement is true:
I need to group every customer id with its corresponding latest access! How this can be done?
Then you can simply do:
select a.name_id, max(a2.date)
from access a
group by a.name_id;
You do not need the customers table because:
All customers are in access, so the left join is not necessary.
You need no columns from customers.

Depending on the value of a column in a table Get data from two different tables

I have three tables USERS,COMPANIES,ORGANIZATIONS
USERS contains: USER_ID, USER_OWNER_ID, OWNER_TYPE, USER_NAME
COMPANIES contains: COMPANY_ID , COMPANY_NAME
ORGANIZATIONS contains: ORGANIZATION_ID, ORGANIZATION_NAME
My requirement is, I have to get the COMPANIES.COMPANY_NAME if USERS.OWNER_TYPE is 20 and should get the ORGANIZATIONS.ORGANIZATION_NAME if USERS.OWNER_TYPE is 30
So, I used the following query
SELECT US.USER_NAME,
US.USER_OWNER_ID,
IF (
US.OWNER_TYPE=20, ORG.ORGANIZATION_NAME, CO.COMPANY_NAME
) AS NAME
FROM USERS US,
COMPANIES CO,
ORGANIZATIONS ORG
WHERE (US.OWNER_TYPE=20 AND US.USER_OWNER_ID=ORG.ORGANIZATION_ID)
OR
(US.OWNER_TYPE=30 AND US.USER_OWNER_ID=CO.COMPANY_ID)
Problem here is I get repeated records of OWNER_TYPE=30 from OWNERS Table.
Can someone help me with this query?
You can try
SELECT us.user_name,
us.user_owner_id,
COALESCE(co.company_name, org.organization_name) AS name
FROM users us LEFT JOIN companies co
ON us.user_owner_id = co.company_id
AND us.owner_type = 30 LEFT JOIN organizations org
ON us.user_owner_id = org.organization_id
AND us.owner_type = 20
Sample output:
| USER_NAME | USER_OWNER_ID | NAME |
|-----------|---------------|---------------|
| User1 | 1 | Organization1 |
| User2 | 1 | Company1 |
Here is SQLFiddle demo