Ordering Records by the contents of Related Table - mysql

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.

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.

SQL script does not return the correct table

I have tables as follows:
CREATE TABLE SKILL(
sname VARCHAR(30) NOT NULL,
CONSTRAINT SKILL_pkey PRIMARY KEY ( sname ) );
CREATE TABLE APPLICANT(
anumber DECIMAL(6) NOT NULL,
fname VARCHAR(20) NOT NULL,
lname VARCHAR(30) NOT NULL,
dob DATE NOT NULL,
city VARCHAR(30) NOT NULL,
state VARCHAR(20) NOT NULL,
phone DECIMAL(10) NOT NULL,
fax DECIMAL(10) ,
email VARCHAR(50) ,
CONSTRAINT APPLICANT_pkey PRIMARY KEY ( anumber ) );
CREATE TABLE SPOSSESSED(
anumber DECIMAL(6) NOT NULL,
sname VARCHAR(30) NOT NULL,
slevel DECIMAL(2) NOT NULL,
CONSTRAINT SPOSSESSED_pkey PRIMARY KEY ( anumber, sname ),
CONSTRAINT SPOSSESSED_fkey1 FOREIGN KEY ( anumber )
REFERENCES APPLICANT ( anumber )
ON DELETE CASCADE,
CONSTRAINT SPOSSESSED_fkey2 FOREIGN KEY ( sname )
REFERENCES SKILL ( sname ),
CONSTRAINT SPOSSESSED_check1 CHECK ( slevel IN
( 1,2,3,4,5,6,7,8,9,10 ) ) );
I was ordered to:
Create a relational table that contains information about the names of all skills and the largest skill level possessed by an applicant and a number of applicant who possesses a skill at the highest level. Ignore the skills not possessed by any applicant. All data must be loaded into the table by the same SQL statement that creates the table. Enforce the appropriate primary key and referential integrity constraints (if any) after data is loaded.
From what I understood, I came up with 2 separate scripts to achieve the selection first:
SELECT * FROM SKILL;
SELECT MAX(SPOSSESSED.slevel), APPLICANT.anumber
FROM APPLICANT RIGHT OUTER JOIN SPOSSESSED
ON APPLICANT.anumber = SPOSSESSED.anumber
GROUP BY anumber;
I don't know if I did the selection right or not? Can anyone help? The more I read the requirement the more I feel confused.
EDIT #1:
Sample Data
SKILL:
INSERT INTO SKILL VALUES ( 'C++ programming' );
INSERT INTO SKILL VALUES ( 'C programming' );
INSERT INTO SKILL VALUES ( 'Java programming' );
INSERT INTO SKILL VALUES ( 'SQL programming' );
INSERT INTO SKILL VALUES ( 'driving' );
INSERT INTO SKILL VALUES ( 'painting' );
INSERT INTO SKILL VALUES ( 'cooking' );
APPLICANT:
INSERT INTO APPLICANT VALUES ( 000001, 'Harry', 'Potter', '1980-12-12', 'Perth', 'Western Australia', 645278453, NULL, 'jones#gmail.com' );
INSERT INTO APPLICANT VALUES ( 000002, 'Johnny', 'Walker', '1990-02-13', 'Geelong', 'Victoria', 63569784, 63569785, 'blunder#hotmail.com' );
INSERT INTO APPLICANT VALUES ( 000003, 'Mary', 'Poppins', '1950-01-01', 'Melbourne', 'Victoria', 62389541, NULL, NULL );
INSERT INTO APPLICANT VALUES ( 000004, 'Michael', 'Collins', '1960-05-25', 'Brisbane', 'Queensland', 63336666, NULL, 'mike#hotmail.com');
INSERT INTO APPLICANT VALUES ( 000005, 'Margaret', 'Finch', '1953-12-07', 'Sydney','New South Wales', 64573489, NULL, 'mf#163.com');
INSERT INTO APPLICANT VALUES ( 000006, 'Claudia', 'Kowalewski', '1959-05-03', 'Hobart', 'Tasmania', 64577744, NULL, 'cch#cs.odmg.org');
INSERT INTO APPLICANT VALUES ( 000007, 'James', 'Bond', '1960-06-01','Perth', 'Western Australia', 645278434, NULL, 'james#bigpond.com');
SPOSSESSED:
INSERT INTO SPOSSESSED VALUES ( 000001, 'Java programming', 9 );
INSERT INTO SPOSSESSED VALUES ( 000001, 'C programming', 4 );
INSERT INTO SPOSSESSED VALUES ( 000001, 'cooking', 9 );
INSERT INTO SPOSSESSED VALUES ( 000002, 'Java programming', 9 );
INSERT INTO SPOSSESSED VALUES ( 000002, 'driving', 9 );
INSERT INTO SPOSSESSED VALUES ( 000003, 'C++ programming', 10 );
INSERT INTO SPOSSESSED VALUES ( 000003, 'Java programming', 9 );
INSERT INTO SPOSSESSED VALUES ( 000003, 'painting', 5 );
INSERT INTO SPOSSESSED VALUES ( 000005, 'SQL programming', 6 );
INSERT INTO SPOSSESSED VALUES ( 000006, 'SQL programming', 8 );
INSERT INTO SPOSSESSED VALUES ( 000007, 'SQL programming', 9 );
INSERT INTO SPOSSESSED VALUES ( 000007, 'cooking', 10 );
I don't really understand what I was required to do so I ask you to see how do you interpret it.
But from my understanding, it should show a table with sname, highest slevel for that sname and anumber with the highest slevel in that sname.
This is as specific as I can go...
The following query will create a list of all skills, and the applicants with the highest skill level for each skill.
SELECT
c.`anumber`,
a.`sname`
FROM `SPOSSESSED` a
JOIN (
SELECT
`sname`
MAX(`slevel`) as `slevel`
FROM `SPOSSESSED`
GROUP BY `sname`
) b
ON b.`sname` = a.`sname` AND b.`slevel` = a.`slevel`
JOIN `APPLICANT` c
ON c.`anumber` = a.`anumber`
GROUP BY a.`sname`, c.`anumber`
If instead of a list of applicants with the highest skill level for each skill, you want a count of applicants with the highest skill level for each skill,
you might try this:
SELECT
a.`sname`,
a.`slevel`,
count(DISTINCT c.`anumber`) as `numapplicants`
FROM `SPOSSESSED` a
JOIN (
SELECT
`sname`
MAX(`slevel`) as `slevel`
FROM `SPOSSESSED`
GROUP BY `sname`
) b
ON b.`sname` = a.`sname` AND b.`slevel` = a.`slevel`
JOIN `APPLICANT` c
ON c.`anumber` = a.`anumber`
GROUP BY a.`sname`, a.`slevel`
Not tested, and may have a typo.

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 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.

MySQL INNER JOIN of 3 tables with count and totals

I have the following sample database set up -
CREATE TABLE IF NOT EXISTS `companies`(
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`company` varchar(75) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
INSERT INTO `companies` (`id`, `company`) VALUES
(1, 'Acme Widget Company'),
(2, 'Intrepid Inc.'),
(3, 'Allied Corp.');
CREATE TABLE IF NOT EXISTS `companies_customers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`company_id` int(11) NOT NULL,
`customer_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
INSERT INTO `companies_customers` (`id`, `company_id`, `customer_id`) VALUES
(1, 2, 1),
(2, 2, 2),
(3, 2, 4),
(4, 1, 3),
(5, 1, 1);
CREATE TABLE IF NOT EXISTS `customers` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`firstname` varchar(25) NOT NULL,
`lastname` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
INSERT INTO `customers` (`id`, `firstname`, `lastname`) VALUES
(1, 'John', 'Smith'),
(2, 'Sue', 'Jones'),
(3, 'David', 'Flanders'),
(4, 'Kathy', 'Freeman');
CREATE TABLE IF NOT EXISTS `orders` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`customer_id` int(11) NOT NULL,
`amount` decimal(10,0) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
INSERT INTO `orders` (`id`, `customer_id`, `amount`) VALUES
(1, 1, 500),
(2, 3, 1000),
(3, 1, 250),
(4, 4, 800),
(5, 4, 100);
I need to write a query which retrieves a list of all company names, a count of the number of customers in each company, and a sum of the customers orders in each company, like this -
Company Total Customers All Orders Total
Acme Widget Company 2 750
Intrepid Inc. 3 1650
Allied Corp. 0 0
I nearly have it resolved with the following SQL -
SELECT company AS 'Company', customersCount AS 'Total Customers', customerOrdersTotal AS 'All Orders Total'
FROM
( SELECT cc.customer_id, SUM(innerQuery.ordersTotal) customerOrdersTotal
FROM (SELECT cu.id customerId, SUM(amount) ordersTotal
FROM customers cu
JOIN orders o ON o.customer_id = cu.id
GROUP BY customerId
) innerQuery
JOIN companies_customers cc ON innerQuery.customerId = cc.customer_id
GROUP BY cc.customer_id
) inner_1
RIGHT JOIN
( SELECT cc.id, c.company, COUNT(*) customersCount
FROM companies c
JOIN companies_customers cc ON c.id = cc.company_id
GROUP BY c.id
) inner_2
ON inner_1.customer_id = inner_2.id
It does not print out the company (Allied) without a customer or total. So close, I just need a nudge in the right direction. Thanks.
Since the orders are linked to the companies via the customers, I don't think you need to perform two separate subqueries and join them; rather, I think you can just write:
SELECT companies.company AS "Company",
IFNULL(COUNT(DISTINCT companies_customers.customer_id), 0) AS "Total Customers",
IFNULL(SUM(orders.amount), 0) AS "All Orders Total"
FROM companies
LEFT
JOIN companies_customers
ON companies_customers.company_id = companies.id
LEFT
JOIN orders
ON orders.customer_id = companies_customers.customer_id
GROUP
BY companies.id
;
Edited to add: That said, I have to say that the schema doesn't really make sense to me. You have a many-to-many relationship between customers and companies — so, for example, John Smith is a customer of Acme Widget Company and of Intrepid Inc. — but then orders are just a property of the customer, not of the company. This means that if an order belongs to John Smith, then it necessarily belongs both to Acme Widget Company and to Intrepid Inc.. I don't think that can be right. Instead of having a customer_id field, I think orders needs to have a companies_customers_id field.
I have 3 table that to keep team,tournament_round AND score_team_member about competition TEAM_A Vs TEAM_B ,multiple of round.(1,2,3...n) and multiple of members of team there is score by oneself.This code above are useful very much.
SELECT team.name AS "TEAM",team.id,
IFNULL(COUNT(DISTINCT `tournament_round`.id), 0) AS "TotalWin",
IFNULL(SUM(`score_team_member`.`score`)/(select count(*) from `team_member`where team_id=team.id group by team_id ), 0) AS "ScoreofTeam"
FROM `team`
LEFT
JOIN `tournament_round`
ON `tournament_round`.team_winner_id = `team`.id
LEFT
JOIN `score_team_member`
ON `score_team_member`.team_id = `team`.id
WHERE `team`.thematch_id='6' AND `team`.`category1`='MEP'
GROUP BY `team`.id ORDER by `TotalWin`DESC ,`ScoreofTeam` DESC
Sample out put click here JPG
Table Designer JPG