So I have the following query which fetches Active Competitions within an organisation and also tries to fetch the user who is leading the competition.
Currently the query correctly fetches the active competitions, and the totalPoints for each user. It now grabs all users, I only want it to grab the top user, so I am assuming the solution lies in the GROUP BY query, some sort of LIMIT?
In this image, you can see the results I am getting. As you can see, I am getting every user for each competition, where I only need the top user for each competition.
http://i.imgur.com/5OXen4e.png
Any idea on how I could solve this?
SELECT c.competitionId, c.name, c.start_date, c.end_date, a.userid, u.name, u.profilePic ,
SUM(activity_weight) AS totalPoints
FROM activity_entries a INNER JOIN users1 u ON u.id = a.userid INNER JOIN competitions c ON c.competitionId = a.competitionId
WHERE c.organisationId = 1 AND c.start_date < now() AND c.end_date > now()
GROUP BY a.userid, c.competitionId ORDER BY c.id DESC
There is a better way. Just run one query with and join to the competitions table. The second query you posted shows that you know how to join tables.
Related
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
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
;
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!
I have a table for referred users (contains an email address and date columns) and a table for users.
I run to get the top referers:
SELECT count(r.Email) as count, r.Email
FROM refs r
WHERE r.referredOn > '2011-12-13'
GROUP BY email
ORDER BY count DESC
But I want to join this with the users table so it displays with other data in the user table, I thought a join would work. Left join becuase emails may be entered incorrectly, some people put first name etc under refs.Email
SELECT count(r.Email) as count, r.Email, u.*
FROM refs r LEFT JOIN users u ON u.email_primary = r.Email
WHERE r.referredOn > '2011-12-13'
GROUP BY email
ORDER BY count DESC
With the above query the count is incorrect, but I don't know why.
Try this one:
SELECT count(r.Email) as count, r.Email
FROM refs r
INNER JOIN users u ON u.email_primary = r.Email
WHERE r.referredOn > '2011-12-13'
GROUP BY email
ORDER BY count DESC
if your adding new column from users u you also need to add it on your group by clause.
Regards
Unfortunately, a LEFT JOIN wont help you here; what this type of join says is give me all the rows in users that match my email, as well as all the rows that have no match on email. If the email doesn't match, then they wont come back as you want.
So you can't use a the left join condition here the way you want.
If you enforced the fact that they had to enter an email everytime, and it was a valid email etc, then you could use an INNER JOIN.
JOINs are usually used to follow referential integrity. So, for example, I have a user with an id in one table, and another table with the column userid - there is a strong relationship between the two tables I can join on.
Jeft Atwood has a good explantion of how joins work.
SEE if this will help you:
SELECT e.count, e.email, u.col1, u.col2 -- etc
FROM (
SELECT count(r.Email) as count, r.Email
FROM refs r
WHERE r.referredOn > '2011-12-13'
GROUP BY email
) e
INNER JOIN
users u ON u.email_primary = e.Email
Instead of a direct join, you could TRY to use your counting query as a subquery-table type..
I wrote this query
SELECT *, count(r.Email) as count FROM refs r
LEFT OUTER JOIN users u ON r.email = u.email_primary
WHERE u.uid IS NOT NULL
GROUP BY u.uid
ORDER BY count DESC
Which showed me that the reason the count was wrong was because some of the email addresses are used twice in the users table (users sharing 'family' email address), this doubled my count, the above query shows each separate user account.
I have two tables user (one) and transaction (many) and I need to get the average time in days from when a user was created to when they made their first transaction. I'm using AVG(TIMESTAMPDIFF) which is working well, except that the GROUP BY returns an average against every user instead of one single average for all unique users in the transaction table. If I remove the GROUP BY, I get a single average figure but it takes into account multiple transactions from users, whereas I just want to have one per user (the first they made).
Here's my SQL:
SELECT AVG(TIMESTAMPDIFF(DAY, u.date_created, t.transaction_date)) AS average
FROM transaction t
LEFT JOIN user u ON u.id = t.user_id
WHERE t.user_id IS NOT NULL AND t.status = 1
GROUP BY t.user_id;
I'd appreciate it if someone can help me return the average for unique users only. It's fine to break the query down into two, but the tables are large so returning lots of data and putting it back in is a no-go. Thanks in advance.
SELECT AVG(TIMESTAMPDIFF(DAY, S.date_created, S.transaction_date)) AS average
FROM (
SELECT u.date_created, t.transaction_date
FROM transaction t
INNER JOIN user u ON u.id = t.user_id
WHERE t.status = 1
GROUP BY t.user_id
HAVING u.date_created = MIN(u.date_created)
) s
I replaced the LEFT JOIN with an INNER JOIN because I think that's what you want, but it's not 100% equivalant to your WHERE t.user_id IS NOT NULL.
Feel free to put the LEFT JOIN back if need be.
select avg( TIMESTAMPDIFF(DAY, u.date_created, min_tdate) ) as average
from user u
inner join
(select t.user_id, min(t.transaction_date) as min_tdate
from transaction t
where t.status=1;
group by t.user_id
) as min_t
on u.id=min_t.user_id;