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.
Related
I'm having a problem in where i want to count how many medals in total a country has won from both the individual and team competitions does not give me the disered outcome. i have managed so far tocome up with this.
select distinct C.Cname as Country, count(i.medal) as Medals_Won
from individual_results as i, Country as C, participant as p
where (i.Olympian = p.OlympicID and C.Cname = p.country)
union
select distinct C.Cname, count(r.medal) as medals_Won
from team_results as r, Country as C, participant as p, team as t
where (r.team = t.TeamID and t.Member1 = p.OlympicID and C.Cname = p.Country)
group by C.Cname
order by medals_won desc
enter image description here
but i get this result.
even tho if i run the two separate pieces of code i ge the wanted restuls that is enter image description here
You say you can run your query and it gives you a result. This is bad. It indicates that you are MySQL's notorious cheat mode that lets you run invalid queries.
You have something like this:
select ...
union
select ...
group by ...
order by ...
There are two queries the results of which you glue together, namely
select ...
and
select ...
group by ...
So, your first query becomes:
select distinct C.Cname as Country, count(i.medal) as Medals_Won
from individual_results as i, Country as C, participant as p
where (i.Olympian = p.OlympicID and C.Cname = p.country)
You COUNT medals, i.e. you aggregate your data. And there is no GROUP BY clause. So you get one result row from all your data. You say you want to count all rows for which i.medal is not null. But you also want to select the country. The country? Which??? Is there just one country in the tables? And even then your query would be invalid, because still you'd have to tell the DBMS from which row to pick the country. You can pick the maximum country (MAX(C.Cname)) for instance or the minimum country (MIN(C.Cname)), but not the country.
The DBMS should raise an error on this invalid query, but you switched that off.
Make sure in MySQL to always
SET sql_mode = 'ONLY_FULL_GROUP_BY';
It is the default in more recent versions, so either you are working with old software or you switched from good mode to bad mode voluntarily.
And talking of old software: Even at the first moment MySQL was published, comma joins had long been deprecated. They were made redudant in 1992. Please don't ever use commas in your FROM clause. Use explicit joins ([INNER] JOIN, LEFT [OUTER] JOIN, etc.) instead.
As to the task, here is a straight-forward solution with joins:
select
c.cname as country,
coalesce(i.medals, 0) as medals_individual,
coalesce(t.medals, 0) as medals_team,
coalesce(i.medals, 0) + coalesce(t.medals, 0) as medals_total
from country c
left outer join
(
select p.country, count(ir.medal) as medals
from participant p
join individual_results ir on ir.olympian = p.olympicid
group by p.country
) i on on i.country = c.name
left outer join
(
select p.country, count(ir.medal) as medals
from participant p
join team t on t.member1 = p.olympicid
join team_results tr on tr.team = t.teamid
group by p.country
) t on on t.country = c.name
order by medals_total desc;
You should sum the union result for each of the subquery grouped by cname
select t.Cname , sum( t.Medals_Won)
from (
select C.Cname as Country, count(i.medal) Medals_Won
from individual_results i
inner join participant p ON i.Olympian = p.OlympicID
inner join Country C ON C.Cname = p.country
group by C.Cname
union
select distinct C.Cname, count(r.medal)
from team_results as r
inner join team as t ON r.team = t.TeamID
inner join participant as p ON t.Member1 = p.OlympicID
inner join Country as C ON C.Cname = p.Country
group by C.Cname
) t
group by t.Cname
order by sum( t.Medals_Won) desc
I am working on this project at my university, where I need to create a query to the database. I want the query to return the company with most movies in the given genre. At the moment I have this query, but this only return one company, but there can probably be more than one.
SELECT CompanyID, CategoryID, COUNT(*) as NumberOfMovies
FROM Movie
NATURAL JOIN CategoryFilm
NATURAL JOIN Category
NATUAL JOIN Comapny
GROUP BY CategoryID, CompanyID
Order by NumberOfMovies DESC LIMIT 1
I beleave I will need a "having" in here.
pls try this, it may because you added limit 1, which only show 1st retrieved record
SELECT CompanyID, CategoryID, COUNT(*) as NumberOfMovies
FROM Movie
NATURAL JOIN CategoryFilm
NATURAL JOIN Category
NATURAL JOIN Comapny
GROUP BY CategoryID, CompanyID
Order by NumberOfMovies DESC
I assume by "category" you mean "genre" -- or that they are the same thing.
Do not use NATURAL JOIN. It does not even use properly declared foreign key relationships, instead relying merely on name similarity between tables. It is dangerous because the columns used are not specified and can introduce hard-to-debug errors. I often refer to it as an "abomination" because it does not take table declarations into account.
If you have a given category, then I would expect a WHERE clause:
SELECT CompanyID, COUNT(*) as NumberOfMovies
FROM Movie m JOIN
CategoryFilm cf
ON cf.movie_id = m.movie_id JOIN
Company c
ON c.company_id = m.company_id
WHERE cf.category_id = ?
GROUP BY CategoryID
ORDER BY NumberOfMovies DESC
LIMIT 1;
If you want to allow ties, you can use window function rank():
select *
from (
select
co.companyID,
ca.categoryID,
count(*) NumberOfMovies,
rank() over(partition by c.categoryID order by count(*) desc) rn
from movie m
inner join categoryFilm cf on cf.movieID = m.movieID
inner join category ca on ca.categoryID = cf.categoryID
inner join company co on co.companyID = m.companyID
group by co.companyID, ca.categoryID
) t
where rn = 1
order by ca.categoryID
This gives you the top company for each and every category, ties included. If you want to filter on a given category, you can just add a where clause to the inner query.
Side note: do not use natural joins: they are error-prone. I rewrote the query to use inner joins instead (I made a few assumptions on the relations).
So I have the below database structure
TABLES ------- Columns
person: id, name, salary, address
group: id, name
person_group: person_id, groud_id
So here is my query which is used to get all persons along with the groups they are associated with
SELECT p.id, p.name,
group_concat(g.name) as groups
FROM person_group pg, group g, person p
WHERE pg.group_id = g.id AND pg.novel_id = n.id
GROUP BY ng.person_id
So this query gives me data like
id name groups
2345 John Admin, SuperAdmin, RedHat
But the problem is: if that person doesn't belong to any group, the query doesn't return that person!
Any would be appreciated!
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
That is exactly your problem here. When you are writing more than one table in the FROM clause, you should be thinking "what type of JOIN do I need". If you had that thought, you would immediate realize that you need an outer join to do what you want:
SELECT p.id, p.name, group_concat(g.name) as groups
FROM person p LEFT JOIN
person_group pg
ON pg.person_id = p.id LEFT JOIN
group g
ON pg.group_id = g.id
GROUP BY p.id, p.name;
If you don't know what an outer join is, then that is all the more reason to use the proper, explicit syntax, so you can learn.
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.
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.