Getting unexpected result while apllying Join SQL query - mysql

I am fetching data from 4 different tables:
leads
payu_transactions
corporate_user_rides
corporate_users
And there are some conditions:
user rides should be grater than 0
There should be some number of registered and active users
There will be some time period
I have written some SQL queries but i am not getting expected result-
The problem is with number of rides count and user count.
For e.g-
Lets say corporate x actually having 38 rides and 23 users but it's showing 7866 rides and 7866 users.
Another corporate y is actually having 18 rides and 5 users but it's showing 90 rides and 90 users.
Can anyone please help, i am not sure what's i am doing here.
I tried this-
query
SELECT l.id AS leadId,
l.corporate_id AS CorporateID,
"P-1" AS priority,
l.source,
l.user_name AS FirstName,
l.user_name AS LastName,
l.corporate_name AS corpName,
l.user_mail_id AS email,
l.phone_number AS phone,
l.created_At AS leadCreation,
l.comments,
Count(CU.id) AS users,
Count(CUR.id) AS rides,
PUT.amount AS payment
FROM leads l
LEFT JOIN payu_transactions PUT
ON l.user_mail_id = PUT.email
LEFT JOIN corporate_user_rides CUR
ON l.corporate_id = CUR.corporate_id
LEFT JOIN corporate_users CU
ON l.corporate_id = CU.corporate_id
WHERE l.created_at BETWEEN '2015-03-16 12:00:00' AND '2016-03-17 12:00:00'
GROUP BY l.user_mail_id
HAVING Count(CUR.id) > 0
AND Count(CU.id) > 0
AND Count(CASE
WHEN CU.status IN ( 'active' ) THEN 1
END) > 0;
Help will be appreciated.

Use Count (Distinct column.name) instead of Count(column.name).

Related

Sum user hours and get avarage, include users who haven't added any hours yet

This is a follow up question to my previous one:
SQL Query multiple sums and avarage of total
I got the previous question working with Madhur Bhaiya's answer:
SELECT SUM(h.hours) / COUNT(DISTINCT h.USER_ID) AS daily_average
FROM hours AS h
WHERE h.date = CURDATE()
Though I realised that I have a follow up question which is:
In my hours table I have two users who have reported their time, though I'd like it to count on the avarage of all the users that exists.
The hours database looks like this:
#USER_ID #HOURS #DATE
1 2 2018-01-01
1 1 2018-01-01
2 5 2018-01-01
1 3 2018-01-02
2 8 2018-01-02
2 1 2018-01-02
That information is in my 'users' database, which looks like this:
#USER_ID #USER_NAME
1 aaa
2 bbb
3 ccc
Any idéas on how to do this? I assume I'd have to join the tables 'hours' and 'users'?
The desired output will be (BASED ON 2018-01-01):
(HIDDEN INFO: USER 1 TOTAL = 3)
(HIDDEN INFO: USER 2 TOTAL = 5)
(HIDDEN INFO: USER 3 TOTAL = 0)
**AVARAGE: 2,666666667**
SELECT SUM(h.hours) / COUNT(DISTINCT u.USER_ID) AS daily_average
FROM hours AS h
RIGHT JOIN users u ON h.USER_ID = u.USER_ID
WHERE h.date = CURDATE()
Your issue of not taking into account users that haven't recorded any hours is that they don't exist on the hours table, so using the count of distinct users on the hours table isn't what you are looking for.
If you join the users table you can get the count of all users in the system rather than ones that haven't recorded hours, this should get you your average for all users, not just the ones that have recorded hours.
use left join
select SUM(h.hours) / COUNT(DISTINCT users.USER_ID) AS daily_averag
from users left join hours on users.USER_ID=hour.user_id
You want a LEFT JOIN and to put the condition for hours in the ON clause:
SELECT SUM(h.hours) / COUNT(DISTINCT u.user_id) as daily_average
FROM users u LEFT JOIN
hours h
ON h.user_id = u.user_id and h.date = CURDATE();
The above is totally correct. However, it might be more performant to just use a subquery on users:
SELECT SUM(h.hours) / (SELECT COUNT(*) FROM users) as daily_average
FROM hours h
WHERE h.date = CURDATE();

mysql query to show results above an average that uses two tables in its sum

I want to have a query that displays only contract costs above average along with the contract id and I create my average with this:
SELECT AVG(average_cost)
FROM (
SELECT SUM(contracts.hours*staff.rate) AS average_cost
FROM contracts
INNER JOIN staff ON contracts.staff_id = staff.staff_id
GROUP BY contracts.contract_id
) AS inner;
I would like the results to show contract_id as well as group by it, even if it all it shows is the contract_id for the results above the average. Just having a hard time getting a query to show results above average with this average that is more complicated than I'm use to. Help appreciated, thanks.
edit* with some sample data, the tables are more complex than this but I hope this helps with some understanding
contracts
contract_id hours staff_id
55 30 10
45 25 11
43 30 12
41 12 11
67 20 12
49 20 13
staff
staff_id rate
10 50
11 45
12 80
13 45
So the average contract cost of above is 1,344.167 or there abouts. For this example I would want the results to show the contract_id for the contracts that cost above the average.
results
contract_id
55
43
67
Here is one method:
SELECT c.contract_id, SUM(c.hours*s.rate) AS cost
FROM contracts c INNER JOIN
staff s
ON c.staff_id = s.staff_id
GROUP BY c.contract_id
HAVING cost > (SELECT AVG(average_cost)
FROM (SELECT SUM(c.hours*s.rate) AS average_cost
FROM contracts c INNER JOIN
staff s
ON c.staff_id = s.staff_id
GROUP BY c.contract_id
) sc
);
As much I understand with your question, I think you are looking for this:
select contract_id
from contracts join staff on (contracts.staff_id = staff.staff_id)
where (hours*rate) >
(select avg(hours*rate)
from contracts join staff on (contracts.staff_id = staff.staff_id)
)
I have my example that can help you:
SELECT first_name, last_name, invoice_amount
FROM students
INNER JOIN invoices
ON students.id_student = invoices.id_student
WHERE invoice_amount > (select avg(invoice_amount) from invoices)

MySQL where statement after left join

I am writing a hockey stat database. I have the need to calculate how many players were on the ice when a goal is scored.
I have set up the following sqlfiddle:
http://sqlfiddle.com/#!9/ed8fa
problem I am having is how to filter the results such that only goals that are scored at regular strength (shot type "reg") or goals that are scored while shorthanded (shot type "sh") count towards this total.
I need all players to be listed in the output, even if their number is zero. After finding the players "Plus rating", I will calculate each players "minus rating" and subtract the two. Once I figure out how to accurately find the "Plus rating", I should be able to figure out how to do the rest.
For the given data in the sqlfiddle, the desired output should be:
player_id Plus_count
20 1
21 0
22 2
23 1
24 1
25 0
26 1
27 1
28 1
29 0
30 0
31 2
32 1
33 0
I am having trouble figuring out how the join would work such that I can use where to filter out all goals that are "pp".
Thanks for any pointers you might be able to give...
adding what I have tried. This is from my dev db, so just slightly different from the sqlfiddle:
SELECT players.player_id as pp_id,
COALESCE(plus_players.count, 0) as Plus_Count
FROM players
LEFT JOIN (SELECT plus_players.fk_player_id, COUNT(*) as count
FROM plus_players
GROUP BY plus_players.fk_player_id) plus_players
ON plus_players.fk_player_id = players.player_id
left join (select * from shots_for
where regular_powerplay_shorthanded = 'reg' or regular_powerplay_shorthanded = 'sh') sf on sf.fk_player_id = players.player_id
union
SELECT players.player_id as pp_id,
COALESCE(plus_players.count, 0) as Plus_Count
FROM players
LEFT JOIN (SELECT plus_players.fk_player_id, COUNT(*) as count
FROM plus_players
GROUP BY plus_players.fk_player_id) plus_players
ON plus_players.fk_player_id = players.player_id
right join (select * from shots_for
where regular_powerplay_shorthanded = 'reg' or regular_powerplay_shorthanded = 'sh') sf2 on sf2.fk_player_id = players.player_id
left join goals_for on goals_for.fk_shot_for_id = sf2.shot_for_id
where regular_powerplay_shorthanded = 'reg' or regular_powerplay_shorthanded = 'sh'
you can see my various attempts above to use the where to eliminate the "pp" goals.

MYSQL: Summary Data Query SQL

So, I have this:
SELECT COUNT(mailing_recipient_id) AS Total_Recipient,
(SELECT COUNT(mailing_recipient_click_id)
ORDER BY(mailing_recipient_click_type_id)) AS Open_Count,
(SELECT COUNT(cons_action_contribution_id)) AS Total_Donations,
(SELECT COUNT(cons_id) ORDER BY cons_action_contribution_id) AS Donations_Per_Recipient
FROM cons LEFT JOIN mailing_recipient
ON cons.cons_id =mailing_recipient.cons_id
JOIN mailing
ON mailing_recipient.mailing_id = mailing.mailing_id
JOIN mailing_recipient_click
ON mailing_recipient_click.mailing_recipient_id = mailing_recipient.mailing_recipient_id
JOIN cons_action_contribution
ON cons_action_contribution.con_id = cons.cons_id
GROUP BY(mailing_id);
What I am hoping to achieve is a summary including recipient count, open count, opens per recipient, click count, clicks per recipient, number of donation, and donations per recipient.
That is not what I am a getting, and I am unsure why.
mailing_recipient_click_id shows if someone open/clicked the email.
mailing_recipient_click_type_id (1=click, 2=open)
I'm failing to get tables now, but What I am hoping to achieve is the following:
Mailing Recipient Open Open_per Clicks Click_per Donation Donation_per
1 10000 5000 5 4000 3 500 2
2 5000 2500 1 4000 1 50 1

Get sum of value with inner join mysql

I have a table for terminal
Id status
1 Online
2 Offline
3 Offline
and I have a separate table where I can find the total hours/date of the up and downtime.
total_time
Id up down
1 10 14
2 20 4
3 15 9
1 5 19
2 4 20
3 10 14
I want to display the terminal id, status and the TOTAL up and downtime(1 = 15(up), 2 = 24(up), 3 = 25(up). I'm using inner join and I have no idea how i will be able to get the sum of the up and downtime..
SELECT terminal.Id, terminal.status, total_time.Id, SUM(total_time.up),SUM(total_time.down)
FROM terminal
INNER JOIN total_time
ON terminal.Id = total_time.Id
WHERE terminal.Id = total_time.Id
Something like this should do the trick. I am interpreting your question as asking for only the sum of the time of the current status. If this is not what you want (and maybe you want the sum of both times), please let me know.
SELECT t.id, t.status, IF(t.status = 'Online', ttlTime.upTime, ttlTime.downTime) as totalTime
FROM terminal t
JOIN
(SELECT tt.id, SUM(tt.up) as upTime, SUM(tt.down) AS downTime
FROM total_time tt
GROUP BY tt.id) ttlTime ON t.id = ttlTime.id
See the SQLFiddle
You get "inner sums" by using the GROUP BY clause.
Try:
SELECT terminal.Id, SUM(total_time.up), SUM(total_time.down)
FROM terminal
INNER JOIN total_time
ON terminal.Id = total_time.Id
GROUP BY terminal.Id
SELECT DISTINCT terminal.Id, terminal.status, total_time.Id, SUM(total_time.up),SUM(total_time.down)
FROM terminal
INNER JOIN total_time
ON terminal.Id = total_time.Id
Should do it. The DISTINCT clause acts as a filter to remove duplicate records from a result set.