MySQL select count with join - mysql

I am trying to get a list of data from multiple tables in a view for analytics - most of the data comes from one table and then I need to get the counts from multiple other tables to show number of logins, number of users and so on.
I am using the below query (simplified to show only some rows and one join):
Select
companies.company_name, companies.last_login, companies.last_ip,
(SELECT COUNT(*) FROM auditing_master GROUP BY company_id) AS audit_count
From
companies
Left Join
auditing_master On auditing_master.company_id = companies.id
Group by
companies.id
When I run this I get an error:
#2014 - Commands out of sync; you can't run this command now
If I run it without the GROUP BY in the SELECT COUNT (*) then it doesn't give any error but it returns a count of all entries in the auditing_master table regardless of which company it refers to.
How can I get a single query to show me the required data from the companies table whilst also showing a total from auditing master (and others) grouped by the company ID?
Edit
Code when using multiple count/joins:
Select
c.company_name, c.last_login, c.last_ip,
COUNT(am.company_id) AS audit_count,
COUNT(u.company_id) AS users,
COUNT(e.company_id) AS employees
From
companies c
Left Join
auditing_master am On am.company_id = c.id
Left Join
users u On u.company_id = c.id
Left Join
employees e On e.company_id = c.id
Group by
c.id
This query locally in PHPMyAdmin on WAMP with only around 10 companies takes 7 seconds to complete and give "meanngless" results that don't correlate to anything.
Thanks

Inner queries in the SELECT clause must return a SINGLE VALUE RESULT.
Something similar to that, should bring what u need.
Select
companies.company_name, companies.last_login, companies.last_ip,
COUNT(*) AS audit_count
From
companies
Left Join
auditing_master On auditing_master.company_id = companies.id
Group by
companies.id

Did you try this? (No need a subquery because no where clause into it, and LEFT JOIN already add auditing_master rows grouped by company_id = companies.id)
Select
companies.company_name, companies.last_login, companies.last_ip,
COUNT(company_id) AS audit_count
From
companies
Left Join
auditing_master On auditing_master.company_id = companies.id
Group by
companies.id
EDIT
Maybe if you add IF statement to avoid COUNT when there is no auditing_master for a given company.
SELECT
companies.company_name, companies.last_login, companies.last_ip,
IFNULL(am.company_id,0,COUNT(am.company_id)) AS audit_count
FROM
companies
INNER JOIN
auditing_master am ON auditing_master.company_id = companies.id
GROUP BY
companies.id
Feel free to put the entire SQL... Because the problem can be somewhere else!

Related

MySQL JOIN tables with COUNT values

I have the following tables in my database.I only listed the important columns which can be used for joining.
I need to get the following output
Currently I'm using two seperate queries for each COUNT value
For assigned licenses
select
products.id,products.name,COUNT(assigned_licenses.id)
from
deployment_users
inner join
assigned_licenses
on
deployment_users.id = assigned_licenses.deployment_user_id
inner join
products
on
assigned_licenses.id = products.id
and
deployment_users.customer_id = 10
group by
assigned_licenses.id
;
For total licenses
select
products.id,products.name,COUNT(total_licenses.id)
from
customers
inner join
total_licenses
on
customers.iccode = licenses.iccode
inner join
products
on
total_licenses.id = products.id
and
customers.id = 10
group by
total_licenses.id
;
Since there are more than a 1,000 products that need to be listed,I want to combine them into a single query.How can I do that?
Your specification leaves some room for interpretation (e.g. can a user have assigned licenses without total licenses? if yes my query will fail.) but I would go with this.
SELECT
products.id,
products.name,
Count(Distinct total_licenses.id) As CountTotalLicenses,
Count(Distinct assigned_liceses.deployment_users_id) As CountAssignedLicenses
FROM products
LEFT JOIN total_licenses ON total_licenses.products_id = products.id
LEFT JOIN customers ON customers.iccode = total_licenses.customers_iccode
LEFT JOIN assigned_licenses ON assigned_liceses.total_licenses_id = total_licenses.id
WHERE
customers.id = 10
GROUP BY
products.id,
products.name
For the future it would be awesome if you could paste code as code and not as an image. People cannot simple copy paste snippets of your code and have to type everything again...
Try joining Both of your query
SELECT * FROM (
(First Query) as assigned_licn
INNER JOIN
(Second Query) as total_licn
USING (id)
);

using JOIN and subquery in mysql

I posted a question about 2 weeks ago about 'one to many' relation between SQL tables. Now I have a bit of a different scenario. Basically, there are two tables - coffee_users and coffee_product_registrations. The latter is connected to coffee_users table with 'uid' column. So basically coffee_users.uid = coffee_product_registrations.uid
A single user can have multiple products registered.
What I want to do is to display some product information (from coffee_product_registrations) along with some user information (from coffee_users), BUT retrieve only those rows that have more than 1 product registrations.
So to simplify, here are the steps I need to take:
Join two tables
Select users that have multiple products registered
Display all their products along with their names and stuff
My current SQL query looks like this:
SELECT c.uid, c.name, cpr.model
FROM coffee_users c
JOIN coffee_product_registrations cpr on c.uid = cpr.uid
GROUP BY c.uid
HAVING COUNT(cpr.uid) > 1
This joins the two tables on 'uid' column but displays only 1 row for each user. It selects just users that have multiple products registered.
Now I need to take these IDs and select ALL the products from coffee_product_registrations based on them.
I cannot figure out how to put this in one query.
Replace cpr.*, c.* with columns which you want to extract feom the query
Try this:
SELECT cpr.*, c.*
FROM coffee_product_registrations cpr
INNER JOIN coffee_users c ON c.uid = cpr.uid
INNER JOIN (SELECT cpr.uid
FROM coffee_product_registrations cpr
GROUP BY cpr.uid
HAVING COUNT(DISTINCT cpr.productId) > 1
) AS A ON c.uid = A.uid;

Count function returning wrong value when joined

I am trying to find a count of actions completed along with company details for companies who have more than 10 users.
The code I am using is:
SELECT
c.company_name,
count(a.action) as actions,
count(u.user_id) as users
FROM
companies c
LEFT JOIN
auditing a on c.id=a.company_id
LEFT JOIN
users u on c.id=u.company_id
GROUP BY
c.id
HAVING
count(u.user_id)>10
LIMIT
10
When I run this it displays an incorrect number of actions.
For example, for the first company in the table it returns:
Company 1,111026,111026
whereas it should return:
Company 1,5093,22
I need to get back the number of actions and the number of users for all companies - how can I do this?
try putting in DISTINCT so that way you aren't counting duplicates
SELECT
c.company_name,
count(DISTINCT a.action) as actions,
count(DISTINCT u.user_id) as users
FROM
companies c
LEFT JOIN
auditing a on c.id=a.company_id
LEFT JOIN
users u on c.id=u.company_id
GROUP BY
c.id
HAVING
count(u.user_id)>10
LIMIT
10

Wrong use of inner join function / group function?

I have the following problem with my query:
I have two tables:
Customer
Subscriber
linked together by customer.id=subscriber.customer_id
in the subscriber table, I have records with id_customer=0 (these are email records, that do not have a full customer account)
Now i want to show how many customers I have per day, and how many subscribers with id_customer, and how many subscribers WITH id_customer=0 (emailonlies i call them)
Somehow, i cannot manage to get those emailonlies.
Perhaps it has something to do with not using the right join type.
When i use left join, i get the right amount of customers, but not the right amount of emailonlies. When I use inner join i get the wrong amount of customers. Am i using the group function correctly? i think it has something to do with that.
THIS IS MY QUERY:
` SELECT DATE(c.date_register),
COUNT(DISTINCT c.id) AS newcustomers,
COUNT(DISTINCT s.customer_id) AS newsubscribedcustomers,
COUNT(DISTINCT s.subscriber_id AND s.customer_id=0) AS emailonlies
FROM customer c
LEFT JOIN subscriber s ON s.customer_id=c.id
GROUP BY DATE(c.date_register)
ORDER BY DATE(c.date_register) DESC
LIMIT 10
;`
I'm not entirely sure, but I think in DISTINCT s.subscriber_id AND s.customer_id=0, it runs the AND before the DISTINCT, so the DISTINCT only ever sees true and false.
Why don't you just take
COUNT(DISTINCT s.subscriber_id) - (COUNT(DISTINCT s.customer_id) - 1)?
(The -1 is there because DISTINCT s.customer_id will count 0.)
Got it, only risk is that i get no email onlies if there are no customers on this day, becuase of the left join. But this one works:
SELECT customers.regdatum,customers.customersqty,subscribers.emailonlies
FROM (
(SELECT DATE(c.date_register) AS regdatum,COUNT(DISTINCT c.id) AS customersqty
FROM customer c
GROUP BY DATE(c.date_register)
) AS customers
LEFT JOIN
(SELECT DATE(s.added) AS voegdatum,COUNT(DISTINCT s.subscriber_id) AS emailonlies
FROM subscriber s
WHERE s.customer_id=0
GROUP BY DATE(s.added)
) AS subscribers
ON customers.regdatum=subscribers.voegdatum
)
ORDER BY customers.regdatum DESC
;

Problem using MySQL Join

i have a MySQL SELECT query which fetches data from 6 tables using Mysql JOIN. here is the MySQL query i am using.
SELECT
u.id,u.password,
u.registerDate,
u.lastVisitDate,
u.lastVisitIp,
u.activationString,
u.active,
u.block,
u.gender,
u.contact_id,
c.name,
c.email,
c.pPhone,
c.sPhone,
c.area_id,
a.name as areaName,
a.city_id,
ct.name as cityName,
ct.state_id,
s.name as stateName,
s.country_id,
cn.name as countryName
FROM users u
LEFT JOIN contacts c ON (u.contact_id = c.id)
LEFT JOIN areas a ON (c.area_id = a.id)
LEFT JOIN cities ct ON (a.city_id = ct.id)
LEFT JOIN states s ON (ct.state_id = s.id)
LEFT JOIN countries cn ON (s.country_id = c.id)
although query works perfectly fine it sometimes returns duplicate results if it finds any duplicate values when using LEFT JOIN. for example in contacts table there exist two rows with area id '2' which results in returning another duplicated row. how do i make a query to select only the required result without any duplicate row. is there any different type of MySQL Join i should be using?
thank you
UPDATE :
here is the contacts table, the column area_id may have several duplicate values.
ANSWER :
there was an error in my condition in last LEFT JOIN where i have used (s.country_id = c.id) instead it should be (s.country_id = cn.id) after splitting the query and testing individually i got to track the error. thank you for your response. it works perfectly fine now.
Duplicating the rows like you mentioned seems to indicate a data problem.
If users is your most granular table this shouldn't happen.
I'd guess, then, that it's possible for a single user to have multiple entries in contacts
You could use DISTINCT as mentioned by #dxprog but I think that GROUP BY is more appropriate here. GROUP BY whichever datapoint could potentially be duplicated....
After all, if a user has corresponding contact records, which one are you intending to JOIN to?
You must specify this if you want to remove "duplicates" because, as far as the RDBMS is concerned, the two rows matching
LEFT JOIN contacts c ON (u.contact_id = c.id)
Are, in fact, distinct already
I think a DISTINCT may be what you're looking for:
SELECT DISTINCT
u.id,u.password,
u.registerDate,
u.lastVisitDate,
u.lastVisitIp,
u.activationString,
u.active,
u.block,
u.gender,
u.contact_id,
c.name,
c.email,
c.pPhone,
c.sPhone,
c.area_id,
a.name as areaName,
a.city_id,
ct.name as cityName,
ct.state_id,
s.name as stateName,
s.country_id,
cn.name as countryName
FROM users u
LEFT JOIN contacts c ON (u.contact_id = c.id)
LEFT JOIN areas a ON (c.area_id = a.id)
LEFT JOIN cities ct ON (a.city_id = ct.id)
LEFT JOIN states s ON (ct.state_id = s.id)
LEFT JOIN countries cn ON (s.country_id = c.id)
This should only return rows where the user ID is distinct, though you may not get all the joined data you'd hoped for.