Getting Stratified data from MySQL - 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.

Related

How to join MySQL tables on date range?

I have a source table (TableA) that contains multiple records for each day. I need to left join (on the date field) it to TableB that contains a few records per year.
The problem is that TableA should be joined to the earliest record from TableB where the date from TableA <= the date from TableB.
CREATE TABLE IF NOT EXISTS `tableA` (
`id` int(6) unsigned NOT NULL,
`date` date NOT NULL,
`content` varchar(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `tableA` (`id`, `date`, `content`) VALUES
('1', '2017-10-03', 'The earth is round.'),
('2', '2018-01-01', 'The earth is flat'),
('3', '2018-01-01', 'One hundred angels can dance on the head of a pin'),
('4', '2018-01-02', 'The earth is flat and rests on a bull\'s horn'),
('5', '2018-01-03', 'The earth is like a ball.');
CREATE TABLE IF NOT EXISTS `tableB` (
`date` date NOT NULL,
`content` varchar(200) NOT NULL,
PRIMARY KEY (`date`)
) DEFAULT CHARSET=utf8;
INSERT INTO `tableB` (`date`, `content`) VALUES
('2017-01-01', 'ONE'),
('2017-12-01', 'TWO'),
('2018-01-02', 'THREE'),
('2018-01-05', 'FOUR');
Based on the this SQLFiddle, I'm looking for the following result.
tableA.id | tableB.content
--------------------------
1 | TWO
2 | THREE
3 | THREE
4 | THREE
5 | FOUR
Here is one solution:
SELECT a.id, b.content
FROM TableA a
JOIN TableB b ON b.date = (
SELECT MIN(b2.date)
FROM TableB b2
WHERE b2.date >= a.date
);
I'm not sure whether this is the most efficient way, but it works.

Getting a count of distinct counts in 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;

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;

Ordering Records by the contents of Related Table

I have two tables. One for Salesman and the other for Sales I wish to order the output of the query by the ALPHA sort of the Name of the salesman.
Here is the Table structure:
CREATE TABLE `Salesman` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
PRIMARY KEY (`ID`) );
INSERT INTO `Salesman` (`Name`) VALUES ('Bill');
INSERT INTO `Salesman` (`Name`) VALUES ('John');
INSERT INTO `Salesman` (`Name`) VALUES ('Dave');
INSERT INTO `Salesman` (`Name`) VALUES ('Mark');
CREATE TABLE `Sales` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Item` INT VARCHAR(45) NULL ,
`Salemesman_ID` INT NULL ,
`Total` INT NUll ,
PRIMARY KEY (`ID`) );
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES ('Pen', '3', '14');
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES ('Rat', '1', '12');
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES ('Car', '2', '1230');
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES('Rabbit', '2', '11');
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES('Towel', '1', '6');
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES('VaporWare', '4','900');
Because the Names in Salesmen in Alpha order are: Bill, Dave, John, Mark
I need the output to be
Rat 1 12 (Bill = 1)
Towel 1 6 (Bill = 1)
Pen 3 14 (Dave = 3)
Car 2 1230 (John = 2)
Rabbit 2 11 (John = 2)
VaporWare 4 900 (Mark = 4)
You can do what you want by joining the tables together:
select s.*
from sales s join
SalesMan sm
on s.Salesman_Id = sm.Id
order by sm.name, sm.id;
I feel the need to add that the table name "Salesman" seems unnecessarily restrictive to only half the human race.