Getting an accurate count on this JOIN - mysql

This query is working fine. It gives a count of contest entrants for whom the contact id in contest_entries is their origin_contact in the person table.
SELECT c.handle, COUNT(*)
FROM `contest_entry` ce,
person p,
contest c
WHERE
p.origin_contact = ce.contact AND
c.id = ce.contest
GROUP BY c.id
I want to now query how many of those records also have at least one record where the contact id matches in email_list_subscription_log BUT that table may have many log records for any one contact id.
How do I write a join that gives me a count that is not inflated by the multiple records?
Should I use a version of my first query to get all of the contact ids into a tmp table and just use that?

Not sure which field is contact id, but you can do something like this:
select c.handle,
count(*) as count
from `contest_entry` ce
inner join person p on p.origin_contact = ce.contact
inner join contest c on c.id = ce.contest
where exists (
select 1
from email_list_subscription_log l
where l.contact_id = ce.contact
)
group by c.id

You ought to deflate the email_list_subscription_log with DISTINCT or GROUP:
SELECT c.handle, COUNT(*)
FROM `contest_entry` ce
JOIN person p ON (p.origin_contact = ce.contact)
JOIN contest c ON (c.id = ce.contest)
JOIN (SELECT DISTINCT contact, email FROM email_list_subscription_log ) AS elsuniq
ON (ce.contact = elsuniq.contact)
[ WHERE ]
GROUP BY c.id
Using GROUP in the subquery you might count the number of records while still returning one row per element:
JOIN (SELECT contact, count(*) AS elsrecords FROM email_list_subscription_log
GROUPY BY contact) AS elsuniq
With this JOIN syntax, the WHERE is not necessary, but I kept it there if you need additional filtering.

Related

Sql Query returns single row, but not all

I am trying to get records with a single SQL query. There are many records in the database but it returns only 1 row.
For example:
it returns record no. 1. If i delete this record then it returns record no. 2. As there are many records. I want it to display all the records.
Here is my Query.
SELECT camp.title, camp.status, c.name, b.base_id, count(s.base_id) as subscribers
FROM campaigns as camp
JOIN company as c ON c.id = camp.company_id
JOIN campaign_numbers as b ON b.campaign_id = camp.id
JOIN base_numbers as s ON s.base_id = b.base_id
WHERE camp.campaign_date = '2017-04-07' AND camp.approved = 1
What i actually want my query to return all the campaigns for current date which is 2017-04-07 and approved status should be 1 but my query is returning only single row, not all campaigns.
If i do this, it returns all..
SELECT title, status
From Campaigns
WHERE campaign_date = '2017-04-07' AND approved = 1
But i also want to show company name and also want to count all subscribers too. WHere am i doing it wrong?
You have an aggregation function in the SELECT with no GROUP BY. In most databases, this would return an error. In MySQL, this is an aggregation query that always returns one row.
Presumably you want the GROUP BY:
GROUP BY camp.title, camp.status, c.name, b.base_id
try as below
SELECT camp.title, camp.status, c.name, b.base_id, count(s.id) as subscribers
FROM campaigns as camp
Left JOIN company as c ON c.id = camp.company_id
Left JOIN campaign_numbers as b ON b.campaign_id = camp.id
Left JOIN base_numbers as s ON s.base_id = b.base_id
WHERE camp.campaign_date = '2017-04-07' AND camp.approved = 1
group by camp.title, camp.status, c.name, b.base_id

MySQL - Group orders count by clients numbers

I want to group order's count to show how many clients have that number of orders.
I have come up with:
select count(*) as quantidade_pedidos, clientes.id
from pedidos
inner join clientes
on pedidos.cliente_id = clientes.id
where pedidos.aprovado = 1
group by quantidade_pedidos
but I just can't group by 'quantidade_pedidos' anyway.
Is there any way to group by a temporary column? Another way of doing this? show how many clients (number) have that number of orders placed?
Example
8 orders placed -> 3 clients have 8 orders placed
etc
Your original query is wrong. You need to group by clientes.id:
select count(*) as quantidade_pedidos, c.id
from pedidos p inner join
clientes c
on p.cliente_id = c.id
where p.aprovado = 1
group by c.id;
In an aggregation query, the unaggregated columns go in the group by, not the aggregated ones.
Also note that table aliases make the query easier to write and to read.
As for the question in the first line, use a subquery:
select quantidade_pedidos, count(*)
from (select count(*) as quantidade_pedidos, c.id
from pedidos p inner join
clientes c
on p.cliente_id = c.id
where p.aprovado = 1
group by c.id
) x
group by quantidade_pedidos;
But given that the query in the question doesn't work, I'm not sure this is what you really want to do.

Need help combining two functional mysql querys into one?

I have this query that will return a list of all of the people associated with Thomas and their ids.
SELECT c.name, c.ID
FROM namesandID s, associations o, namesandID c
WHERE s.name='Thomas' AND o.id = s.ID AND o.associateID = c.ID
GROUP BY c.ID;
Then I have this query that I can manually type in the id number and it will return the correct count of associates.
SELECT count(*) FROM (
SELECT associateID FROM associations WHERE id=18827 GROUP BY associateID
) AS t;
My goal is to have one query that will take Thomas as the name and return three columns that will have his associate their id number an the number of people they are associated with.
Also as some additional information this is a very large database with about 4million rows and 300million associations so any speed increase on either of these queries would be greatly welcomed.
Not tested, however the below should work:
select
c.name,
c.id,
assoc_count.cnt
from
namesandIds s
inner join
associations o on
o.id = s.ID
inner join
namesandId c on
c.ID = o.associateId
left outer join
(
select
id,
count(distinct associateId) as cnt
from
associations
group by
id
) assoc_count on
assoc_count.id = c.ID
where
s.name = 'Thomas'
Not very efficient but
SELECT c.name, c.ID, COUNT(DISTINCT o.associateID)
FROM {the rest of the first query}
should do the trick.

I need to join three tables, group the results by one column, and display the highest value from another column

Say I have three tables:
users with names IDs
emails containing rows which have their email address
messages containing rows which contain the dates and titles of their emails
the second and third tables can all be matched to the first using the user's ID of course.
I want a query which will return each user once only, their email address and the date of their most recent message.
If I use this:
SELECT name,email,title,date
FROM users
JOIN emails ON users.id = emails.user_id
JOIN messages ON messages.user_id = emails.user_id
group by name
order by date desc
I don't get the most recent message, because the ordering has happened after the joining and the grouping. I get one email each from my users, and the emails are sorted by their date.
Can this be done in one join? What am I missing?
Pastebin for a dummy database you can use: http://pastebin.com/1x273aEe -- the actual database is not exactly like this, but it's the same problem.
SELECT a.*, b.*, c.*
FROM users a
INNER JOIN emails b
ON a.ID = b.user_ID
INNER JOIN messages c
ON a.ID = c.user_ID
INNER JOIN
(
SELECT user_id, MAX(date) maxDate
FROM messages
GROUP BY user_ID
) d ON c.user_ID = d.user_ID AND
c.date = d.maxDate
SQLFiddle Demo

MySql query to get count of days spent in each country for each purpose? (Get count of all record in second table present in first table)

I have three tables tl_log, tl_geo_countries,tl_purpose. I am trying to get the count of number of days spent in each country in table 'tl_log' for each purpose in table 'tl_purpose'.
I tried below mysql query
SELECT t.country_id AS countryID,t.reason_id AS reasonID,count(t.reason_id) AS
days,c.name AS country, p.purpose AS purpose
FROM `tl_log` AS t
LEFT JOIN tl_geo_countries AS c ON t.country_id=c.id
LEFT JOIN tl_purpose AS p ON t.reason_id=p.id
GROUP BY t.reason_id,t.country_id ORDER BY days DESC
But landed up with.
I am not able to get the count for purpose for each country in 'tl_log' that is not present in table 'tl_log'. Any help is greatly appreciated. Also, Please let me know if the question is difficult to understand.
Expected Output:
Below is the structure of these three tables
tl_log
tl_geo_countries
tl_purpose
If you want all possible combination of countries and purposes, even those that do not appear on the log table (these will be shown with a count of 0), you can do first a cartesian product of the two tables (a CROSS join) and then LEFT join to the log table:
SELECT
c.id AS countryID,
p.id AS reasonID,
COUNT(t.reason_id) AS days,
c.name AS country,
p.purpose AS purpose
FROM
tl_geo_countries AS c
CROSS JOIN
tl_purpose AS p
LEFT JOIN
tl_log AS t
ON t.country_id = c.id
AND t.reason_id = p.id
GROUP BY
p.id,
c.id
ORDER BY
days DESC ;
If you want the records for only the countries that are present in the log table (but still all possible reason/purposes), a slight modification is needed:
SELECT
c.id AS countryID,
p.id AS reasonID,
COUNT(t.reason_id) AS days,
c.name AS country,
p.purpose AS purpose
FROM
( SELECT DISTINCT
country_id
FROM
tl_log
) AS dc
JOIN
tl_geo_countries AS c
ON c.id = dc.country_id
CROSS JOIN
tl_purpose AS p
LEFT JOIN
tl_log AS t
ON t.country_id = c.id
AND t.reason_id = p.id
GROUP BY
p.id,
c.id
ORDER BY
days DESC ;
LEFT JOIN should be replaced by RIGHT JOIN