Getting a count of distinct counts in mySql - mysql

I have two Tables one for Teams one for Players What I am trying to find out is the total head count table, In other words I want to have a count of the total number of teams that have 2 members, the to all number of teams that have 3 members etc
Here is the database structure.
(Sidebar Question: I'm a newbee here: Is there a better way to post the SQL? )
CREATE TABLE `formsfiles`.`Teams` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
PRIMARY KEY (`ID`) );
INSERT INTO `Teams` (`Name`) VALUES ('Sharks');
INSERT INTO `Teams` (`Name`) VALUES ('Jets');
INSERT INTO `Teams` (`Name`) VALUES ('Fish');
INSERT INTO `Teams` (`Name`) VALUES ('Dodgers');
CREATE TABLE `Players` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
`Team_ID` INT NULL ,
PRIMARY KEY (`ID`) );
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Jim', '1');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Tom', '1');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Harry', '2');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Dave', '2');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Tim', '3');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Trey', '4');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Jay', '4');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Steve', '4');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Chris', '4');
What I want is a count Team sizes.
I would like to see the following output
Team_Size Count
1 1
2 2
4 1

The simplest way would probably be:
select team_count, count(*) from
(select count(*) team_count from players group by team_id) sq
group by team_count
(Although this won't include teams with no players in them.)
SQLFiddle here.

First, you need the team sizes:
select t.id as teamId, count(p.id) as teamSize
from
`Teams` as t
left join `Players` as p on t.id = p.teamId
group by
t.id;
Notice that this will return the teams with zero players too. If you don't want that, use inner join instead of left join.
Now, use this query as a row source for your final query:
select teamSize, count(teamId)
from (
select t.id as teamId, count(p.id) as teamSize
from
`Teams` as t
left join `Players` as p on t.id = p.teamId
group by
t.id) as a
group by teamSize;
Hope this helps
Just one more thing.
If you have big data sets, this query may hang. So it may be best to create a temp table, index it, and run the query on the temp table:
drop table if exists temp_teamSize;
create temporary table temp_teamSize
select t.id as teamId, count(p.id) as teamSize
from
`Teams` as t
left join `Players` as p on t.id = p.teamId
group by
t.id;
alter table temp_teamSize
add unique index idx_teamId(teamId),
add index idx_teamSize(teamSize);
select teamSize, count(teamId)
from temp_teamSize
group by teamSize;

Related

how can I get categories that share at least one product with another given category?

how can i get categories that share at least one product with another given category in sql?
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `p2c`
-- ----------------------------
DROP TABLE IF EXISTS `p2c`;
CREATE TABLE `p2c` (
`products_id` int(11) NOT NULL default '0',
`categories_id` int(11) NOT NULL default '0',
PRIMARY KEY (`products_id`,`categories_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of p2c
-- ----------------------------
INSERT INTO `p2c` VALUES ('1001', '1');
INSERT INTO `p2c` VALUES ('1001', '2');
INSERT INTO `p2c` VALUES ('1002', '1');
INSERT INTO `p2c` VALUES ('1003', '2');
INSERT INTO `p2c` VALUES ('1004', '1');
INSERT INTO `p2c` VALUES ('1004', '2');
INSERT INTO `p2c` VALUES ('1005', '3');
INSERT INTO `p2c` VALUES ('1006', '2');
INSERT INTO `p2c` VALUES ('1006', '3');
INSERT INTO `p2c` VALUES ('1007', '4');
select distinct a.categories_id as categories_associated_with_1
from p2c as a
inner join (select products_id
from p2c
where categories_id=1) as b
on a.products_id=b.products_id
where a.categories_id<>1
something like that :
You make an inner join on same table. The products_id must be identical, and categories_id must be different.
select distinct p2.categories_id
from p2c p1
inner join p2c p2
on p1.products_id = p2.products_id and
p1.categories_id <> p2.categories_id
where p1.categories_id = 1
SqlFiddle
Something like this would do it
SELECT
DISTINCT categories_id
FROM p2c
WHERE
categories_id != 1
AND products_id IN
(SELECT products_id FROM p2c WHERE categories_id = 1)
try out in this fiddle.

Getting List of records with No related records MySQL

I wish to know which team in "TX" have not played a game. (In other words Im looking for a selection of records where there is no related record in the many table.)
Here is the SQL:
(Or if You prefer the sql fiddle is here:http://sqlfiddle.com/#!2/14106 )
CREATE TABLE `Team` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
`State` VARCHAR(45) NULL ,
PRIMARY KEY (`ID`) );
CREATE TABLE `Games` (
`ID` INT NOT NULL AUTO_INCREMENT,
`Team_ID` INT NULL ,
`Game_Day` DATE NULL ,
PRIMARY KEY (`ID`) );
INSERT INTO `Team` (`Name`, `State`) VALUES ('Rams', 'TX');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Rockets', 'OK');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Bombers', 'TX');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Yellow Jackets', 'NV');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Wildcats', 'CT');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Miners', 'CO');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Bolts', 'TX');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('2', '2013-03-16');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('2', '2013-01-01');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('3', '2013-04-16');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('5', '2013-02-02');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('4', '2013-02-12');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('6', '2013-01-09');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('6', '2013-01-01');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('3', '2013-05-01');
I should get the result:
ID Name
1 Rams
7 Bolts
SELECT `ID`, `Name` FROM `TEAM`
WHERE `ID` NOT IN (SELECT DISTINCT(`Team_ID`) from `Games`)
AND `State` = 'TX';
SqlFiddle here.
Use an outer join, selecting only those rows that don't match
SELECT t.*
FROM TEAM t
LEFT JOIN GAMES g ON g.team_id = t.id
WHERE t.state = 'TX'
AND g.team_id is null -- return only rows that *don't* join
This this running in SQL Fiddle
Note that using a join will out-perform a sub-query approach, especially when data sets become large.
You can also left-join to the Games table and filter for where there isn't a corresponding Games row. This is usually faster than NOT IN when the tables have a lot of rows:
SELECT Team.ID, Team.Name
FROM Team
LEFT JOIN Games ON Team.ID = Games.Team_ID
WHERE Team.State = 'TX' AND Games.ID IS NULL;
If there isn't a Games row to go with the Teams row, the Games.ID column will be null in the result, so if you filter on Games.ID IS NULL you'll get all the rows where a team has no games.
There's a SQL Fiddle here.
Hope this would help.
select t.ID,t.NAME
FROM Team t
WHERE t.state = 'TX'
AND t.id NOT IN (SELECT g.TEAM_ID FROM Games g)

Getting a list of records who's

I would like to have a list of all the players in a sports league who are on a team that only has a single member.
Here is the sql:
CREATE TABLE `formsfiles`.`Teams` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
PRIMARY KEY (`ID`) );
INSERT INTO `Teams` (`Name`) VALUES ('Sharks');
INSERT INTO `Teams` (`Name`) VALUES ('Jets');
INSERT INTO `Teams` (`Name`) VALUES ('Fish');
INSERT INTO `Teams` (`Name`) VALUES ('Dodgers');
INSERT INTO `Teams` (`Name`) VALUES ('Pigs');
CREATE TABLE `Players` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
`Team_ID` INT NULL ,
PRIMARY KEY (`ID`) );
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Jim', '1');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Tom', '1');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Harry', '2');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Dave', '2');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Tim', '3');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Trey', '4');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Jay', '4');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Steve', '4');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Ziggy', '5');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Chris', '4');
The Result should give me:
ID Name
5 Tim
9 Ziggy
Not sure how to get them grouped up?
If you want to return the players on a team with only one member you can use:
select p.id, p.name
from players p
where p.Team_ID in (select Team_ID
from players p
group by Team_ID
having count(Team_ID) = 1);
See SQL Fiddle with Demo
Edit, you can also use (moving from comment):
select max(id) id, max(name) name
from players
group by team_id
having count(team_id) = 1;
See SQL Fiddle with Demo
Thanks Bluefeet:
this work wonderfully:
I want to post it here in case someone serches itin the future:
select max(id) id, max(name) name
from players
group by team_id
having count(team_id) = 1;

Getting Stratified data from MySQL

I have two tables. Teams and Players. What I want to do is create a query that tells me some statistical data about the salary of the largest team. Specifically I want a count of how many players make less than 5K. How many make between 5K and 10K ....in increments of 5K to the max player.
Here is the SQL:
CREATE TABLE `formsfiles`.`Teams` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
PRIMARY KEY (`ID`) );
INSERT INTO `Teams` (`Name`) VALUES ('Sharks');
INSERT INTO `Teams` (`Name`) VALUES ('Jets');
INSERT INTO `Teams` (`Name`) VALUES ('Fish');
INSERT INTO `Teams` (`Name`) VALUES ('Dodgers');
CREATE TABLE `Players` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
`Team_ID` INT NULL ,
`Salary` INT NUll ,
PRIMARY KEY (`ID`) );
INSERT INTO `Players` (`Name`, `Team_ID`, salary) VALUES ('Jim', '1', '4800');
INSERT INTO `Players` (`Name`, `Team_ID`, salary) VALUES ('Tom', '1', '12000');
INSERT INTO `Players` (`Name`, `Team_ID`, salary) VALUES ('Harry', '2', '1230');
INSERT INTO `Players` (`Name`, `Team_ID`, salary) VALUES ('Dave', '2', '19870');
INSERT INTO `Players` (`Name`, `Team_ID`, salary) VALUES ('Tim', '3', '1540');
INSERT INTO `Players` (`Name`, `Team_ID`, salary) VALUES ('Trey', '4','7340');
INSERT INTO `Players` (`Name`, `Team_ID`, salary) VALUES ('Jay', '4', '4800');
INSERT INTO `Players` (`Name`, `Team_ID`, salary) VALUES ('Steve', '4','6610');
INSERT INTO `Players` (`Name`, `Team_ID`, salary) VALUES ('Chris', '4','17754');
Given this data: The Dodgers are the largest team (ID =4)
We would like an output of:
0-5000 1
5000-10000 2
10000-15000 0
15000-20000 1
If this code looks familiar it is because it is an evolution of a problem of a prior problem I posted here. Kindly don't beat me down!
Here is my attempt at this. It uses joins to satisfy the conditions:
select sr.range,
SUM(case when p.salary >= sr.low and p.salary < sr.high then 1 else 0 end)
from Players p join
(select t.id
from Players p join
Teams t
on p.team_id = t.id
group by t.team_id
order by SUM(p.salary) desc
limit 1
) team
on p.team_id = team.id cross join
(select '0-5000' as range, 0 as low, 5000 as high union all
select '5000-10000', 5000, 10000 union all
select '10000-15000', 10000, 15000 union all
select '15000-20000', 15000, 20000
) sr
group by sr.range
order by min(sr.low)
Notice the use of a separate query for the ranges, to be sure that you get rows with a count of 0.
This code will do almost what you want
SELECT 5000 * FLOOR(Salary / 5000), count(*)
FROM Players
WHERE Team_ID = 4
GROUP BY FLOOR(Salary / 5000)
It returns the low border of the range and the number of entries
0 1
5000 2
15000 1
Note that it does not return empty ranges.

Missing SQL entries when combining LEFT/INNER JOIN + GROUP BY

I have the following MySQL structure (minimized a lot):
CREATE TABLE `site_movies` (
`id` int(10),
`title` varchar(90),
PRIMARY KEY (`id`)
) ENGINE=MyISAM;
INSERT INTO `site_movies` VALUES(1, 'Borrowers, The');
INSERT INTO `site_movies` VALUES(2, 'Louis C.K.: Chewed Up');
INSERT INTO `site_movies` VALUES(3, 'Louis C.K.: Shameless');
INSERT INTO `site_movies` VALUES(4, 'Vinni-Pukh');
CREATE TABLE `site_movies_directors` (
`id` mediumint(8),
`name` varchar(255),
PRIMARY KEY (`id`)
) ENGINE=MyISAM;
CREATE TABLE `site_movies_directors_connections` (
`movie_id` mediumint(8),
`director_id` mediumint(8)
) ENGINE=MyISAM;
CREATE TABLE `site_movies_seen` (
`object_id` int(10),
`date` varchar(10),
`rating` tinyint(2)
) ENGINE=MyISAM;
INSERT INTO `site_movies_seen` VALUES(1, '0', 4);
INSERT INTO `site_movies_seen` VALUES(2, '1293821757', 5);
INSERT INTO `site_movies_seen` VALUES(3, '1293821758', 7);
INSERT INTO `site_movies_seen` VALUES(4, '0', 6);
And then the following query (also minimized a lot):
SELECT m.title, s.date
FROM site_movies_seen s
INNER JOIN site_movies m ON s.object_id = m.id
LEFT JOIN site_movies_directors_connections AS mdc ON ( m.id = mdc.movie_id )
GROUP BY mdc.movie_id, s.date
ORDER BY s.date ASC
Prints:
title date
Borrowers, The 0
Louis C.K.: Chewed Up 1293821757
Louis C.K.: Shameless 1293821758
Notice that "Vinni-Pukh" is missing because it is the second entry in the _seen table with date = 0. How can I include all entires, even when several entires have the same timestamp?
Change your group by statement to this:
GROUP BY m.id, s.date
Your join condition says m.id = mdc.movie_id, so you might think that these two fields are always equal and therefore it doesn't matter whether you write m.id or mdc.movie_id in your GROUP BY. This is not true because you are using a LEFT JOIN, not an INNER JOIN. This means that mdc.movie_id can be NULL, and all NULL entries go into the same group.
Also, since you aren't selecting any columns from the site_movies_directors_connections you should omit it from the query completely.
SELECT m.title, s.date
FROM site_movies_seen s
INNER JOIN site_movies m ON s.object_id = m.id
GROUP BY m.id, s.date
ORDER BY s.date