SQL connecting table and comparing value in same column - sql

Hello I have these two tables:
Team:
team_id
team_name
division
and
Match:
match_id
match_date
...
Team_team_id
Team_team_id1
Example of the Team data:
(1, Anaheim, P)
(2, Arizona, P)
(3, Boston, S)
(4, Buffalo, M)
(5, Detroit, M)
and Match:
(1, date, 1, 2)
(2, date, 2, 3)
(3, date, 5, 3)
and result should be only Anaheim(played against Arizona in same division)
I want to list only team's names, which played matches only against teams in the same division. How could I do that in SQL and relational algebra? Division is only character value. Thank you for any help...

SELECT t1.team_name AS team_name1,
t2.team_name AS team_name2
FROM team t1
INNER JOIN match m
ON ( t1.team_id = m.team_team_id )
INNER JOIN team t2
ON ( t2.team_id = m.team_team_id1 )
WHERE t1.division = t2.division

Related

How many elements in one column are linked to an element other column?

Consider I have two tables
Courses Program
---------------------------
course_ID program_id
course_title program_name
program_ID
Now, I want to check no of courses(by course_id) offered by each program (program_id).
select c.program_id ,p.program_name, count(course_id)
from courses c
join Program p on c.Program_id =p.Program_id
group by program_id,program_name
If I understood you correctly, you're searching for a GROUP BY and a corresponding aggregate.
--Creating sample tables and data
SELECT course_ID, course_title, program_ID
INTO #courses
FROM (
VALUES (0, 'course_0', 0),
(1, 'course_1', 0),
(2, 'course_2', 0),
(3, 'course_3', 0),
(4, 'course_4', 1),
(5, 'course_5', 1),
(NULL, 'course_6', 1)
) AS C (course_ID, course_title, program_ID)
SELECT program_ID, program_title
INTO #programs
FROM (
VALUES (0, 'program_0'),
(1, 'program_1')
) AS P (program_ID, program_title)
and after that execute the query
SELECT P.program_title, COUNT(C.course_ID) AS courses_amount
FROM #courses C
INNER JOIN #programs P ON C.program_ID = P.program_ID
GROUP BY P.program_ID, P.program_title
So you basically GROUP BY the value to which you to aggregate to and COUNT the 'course_id'.
COUNT(C.course_ID) only counts actual values and will ignore NULLs.
If you want to count the NULLs as well, just use COUNT(*).
EDIT: Forgot the result...
So it'll look like this:
program_title
courses_amount
program_0
4
program_1
2

How to I find the person who has taught the most classes

I want to try and find the employee who has taught the most classes as the position Teacher. So in this I want to print out Nick, as he has taught the most classes as a Teacher.
However, I am getting the error:
ERROR: column "e.name" must appear in the GROUP BY clause or be used in an aggregate function Position: 24
CREATE TABLE employees (
id integer primary key,
name text
);
CREATE TABLE positions (
id integer primary key,
name text
);
CREATE TABLE teaches (
id integer primary key,
class text,
employee integer,
position integer,
foreign key (employee) references employees(id),
foreign key (position) references positions(id)
);
INSERT INTO employees (id, name) VALUES
(1, 'Clive'), (2, 'Johnny'), (3, 'Sam'), (4, 'Nick');
INSERT INTO positions (id, name) VALUES
(1, 'Assistant'), (2, 'Teacher'), (3, 'CEO'), (4, 'Manager');
INSERT INTO teaches (id, class, employee, position) VALUES
(1, 'Dancing', 1, 1), (2, 'Gardening', 1, 2),
(3, 'Dancing', 1, 2), (4, 'Baking', 4, 2),
(5, 'Gardening', 4, 2), (6, 'Gardening', 4, 2),
(7, 'Baseball', 4, 1), (8, 'Baseball', 2, 1),
(9, 'Baseball', 4, 2);
The SQL statement I am trying to use:
SELECT count(t.class), e.name
FROM positions p
JOIN teaches t
ON p.id = t.position
JOIN employees e
ON e.id = t.employee
WHERE p.name = 'Teacher'
GROUP BY t.employee;
I've been working on this on a sql fiddle:
http://www.sqlfiddle.com/#!17/a8e19c/3
Your query looks pretty good. You just need to fix the GROUP BY clause, so it is consistent with the columns in the SELECT clause. Then ORDER BY and LIMIT:
SELECT count(*) cnt_classes, e.name
FROM positions p
INNER JOIN teaches t ON p.id = t.position
INNER JOIN employees e ON e.id = t.employee
WHERE p.name = 'Teacher'
GROUP BY e.id --> primary key of "employees"
ORDER BY cnt_classes DESC --> order by descending count of classes
LIMIT 1 --> keep the first row only
In your select you are using aggregate COUNT that counts all lines in each group (GROUP BY t.employee) but you don't aggregate e.name.
So for Nick you basically select 4 rows each for one class that have two columns - class name and teacher name. Then you ask server to count class names in Nicks group (by his employee id), that aggregates 4 rows into one with value 4 but you don't do anything about teacher name so you are left with invalid structure where you have 1 row for classes count column and 4 rows for teacher name. Same for other teachers. And that's what server is complaining about. Easiest way to fix that is to add e.name to GROUP BY, that will squeeze those 4 rows of same value into one.
To get teacher that teaches most classes you then only need to sort results by class count descending order and limit result count to 1. That will give you result row with highest class count.
Updated fiddle: http://www.sqlfiddle.com/#!17/a8e19c/7
You're getting the error because you need to need to have every column you're selecting (e.name in this example in the GROUP BY clause, otherwise SQL doesn't know how to group and return a count for that column. You'll also want to use TOP(1) and order by if you want to return the person with the most.
SELECT TOP(1) count(*), e.name
FROM teaches t
INNER JOIN positions p ON t.position = p.id
INNER JOIN employees e ON e.id = t.employee
WHERE p.name = 'Teacher'
GROUP BY e.name
ORDER BY count(*) DESC;

Find BAILEY's BLUE BANDANNA

Imagine dance teams (of varying size) can choose one or more outfits and each outfit can have one or more items. All members of a team must have all same outfits and all the items of each outfit, i.e., incomplete outfits are bad -- we want to find those bad outfits.
The tables below define two teams: APPLE and BANANA. Team APPLE has 3 members, team BANANA two members. The APPLEs have chosen a single outfit which has a single item, the YELLOW PANTSUIT outfit, naturally a crowd favorite. Team BANANA have two outfits: RED, and BLUE; but, BAILEY is missing the BANDANNAS item for the BLUE outfit. Awkward.
Let's get BAILEY out of trouble. Create a query to find missing items in the outfits chosen by the teams.
Thanks to #Brits for the SQL below:
Teams and team-members:
CREATE TABLE team (
id int unique,
name text
);
INSERT INTO team (id, name)
VALUES (1, 'APPLE'),
(2, 'BANANA');
CREATE TABLE team_member (
id int unique,
name text,
team_id int references team (id)
);
INSERT INTO team_member (id, name, team_id)
VALUES (1, 'ADAM', 2),
(2, 'BAILEY', 2),
(3, 'CATE', 1),
(4, 'DAVE', 1),
(5, 'ERIN', 1);
Outfits and outfit items:
CREATE TABLE outfit (
id int unique,
name text
);
INSERT INTO outfit (id, name)
VALUES (1, 'RED'),
(2, 'YELLOW'),
(3, 'BLUE');
CREATE TABLE outfit_item (
id int unique,
name text,
outfit_id int references outfit (id)
);
INSERT INTO outfit_item (id, name, outfit_id)
VALUES (1, 'SHORTS', 1),
(2, 'SHIRT', 1),
(3, 'PANTSUIT', 2),
(4, 'BANDANNA', 3),
(5, 'HAT', 3);
Team member outfit items:
CREATE TABLE member_item (
member_id int references team_member (id),
item_id int references outfit_item (id)
);
INSERT INTO member_item (member_id, item_id)
VALUES (1, 1),
(1, 2),
(1, 4),
(1, 5),
(2, 1),
(2, 2),
(2, 5),
(3, 3),
(4, 3),
(5, 3);
Team APPLE's members all have the YELLOW PANTSUIT outfit so the APPLEs are ready to rumble.
Team BANANA chose the RED and BLUE outfits; sadly, I failed to give team BANANA the YELLOW PANTSUIT outfit - they would have killed it, but whatever. Team BANANA's ADAM and BAILEY have the items for the RED outfit, but BAILEY does not have the BANDANNA for the BLUE outfit; let's not let a bandanna get in the way to team BANANA so we need a query to return just:
BANANA BAILEY BLUE BANDANNAS
To find the number of items in an outfit:
SELECT
o.name
, count(*) AS "number of items"
FROM
outfit_item i
, outfit o
WHERE
i.outfit_id = o.id
GROUP BY
i.outfit_id
, o.name
name | number of items
--------+-----------------
RED | 2
BLUE | 2
YELLOW | 1
Similarly, the number of members in a team:
SELECT
t.name
, count(*) AS "number of members"
FROM
team_member m
, team t
WHERE
m.team_id = t.id
GROUP BY
m.team_id
, t.name
name | number of members
--------+-------------------
BANANA | 2
APPLE | 3
That's all well and good, but how do we combine this information so we can bail BAILEY out of this BANANA blunder?
Taking on board the comment "If any member has an outfit item then all team members must have all items in that outfit" I believe the following will do what you are looking for (I'm using a CTE to work out what outfits are associated with each team).
with teamoutfit as (
-- If any mmber of a team has any part of an outfit then that team is linked to that outfit
select distinct te.id as team_id, oft.id as outfit_id from
team te
inner join team_member tm on tm.team_id = te.id
inner join member_item mi on mi.member_id = tm.id
inner join outfit_item oi on oi.id = mi.item_id
inner join outfit oft on oft.id = oi.outfit_id
)
select te.name as team, tm.name as member, of.name as outfit, oi.name as item from
team te
inner join team_member tm on tm.team_id = te.id
inner join teamoutfit tof on tof.team_id = tm.team_id
inner join outfit of on of.id = tof.outfit_id
inner join outfit_item oi on tof.outfit_id = oi.outfit_id
left join member_item mi on oi.id = mi.item_id and tm.id = mi.member_id
where
mi.member_id is null
Output:
| team | member | outfit | item |
|--------|--------|--------|----------|
| BANANA | BAILEY | BLUE | BANDANNA |
I setup a SQL Fiddle you can use to play with this (and perhaps clarify your question if I misunderstood what you are trying to do).
Confirmed to work on postgres, albeit not pretty and am 85% sure this can be simplified. Also, I was a little confused on how outfit and outfit_item tables are related. In the way you laid out the tables, bandanas and hats are are always blue, pantsuits are always yellow and shorts/shirts are always red when you join outfit to outfit_item (outfit.id = outfit_item.outfit_id). The test data and query has been written with that understanding.
select distinct
tm.name as member_name,
t.name as team_name,
o.name as outfit_color,
oi.name as outfit_item
from team_member tm
join team t
on t.id = tm.team_id
join member_items mi
on mi.member_id = tm.id
join(
with outfit_item_count as
(SELECT outfit_id, count(*) AS items
FROM outfit_items
GROUP BY 1)
select mi.member_id, oi.outfit_id, oic.items as items_needed, count(mi.item_id) as member_item_count
from member_items mi
join outfit_items oi on oi.id = mi.item_id
join outfit_item_count oic on oic.outfit_id = oi.outfit_id
group by 1,2,3)z
on z.member_id = tm.id
join outfit_items oi
on oi.outfit_id = z.outfit_id
join outfit o
on o.id = oi.outfit_id
where z.items_needed > z.member_item_count
and oi.id not in (select item_id from member_items)

How to write a single query for the below scenario?

I am new to SQL and I am facing a problem in writing a query for one scenario. I have 3 tables:
Table 1 has actor names and movie-id's
Table1
Actor-ID Actor-name Movies_id
Table 2 has movie-id's and corresponding movie names.
Table2
Movies_id Movies_name
Table 3 has movie-id's and corresponding revenue generated by the movies.
Table3
Movies_id Revenue_generated
I want to write a query to fetch data for the below scenario:
All the movies of any one actor which has earned more than 100 crores.
I haven't mention any data in the tables, so feel free to add data from your side.
You should re-design the database with these tables:
actor (actor_id, name)
movie (movie_id, name, revenue)
actor_movie (actor_id, movie_id)
And the query would be:
select *
from movie
where revenue > 1000000000
and movie_id in
(
select movie_id
from actor_movie
where actor_id = (select actor_id from actor where name = 'Bruce Willis')
);
Data :
INSERT [dbo].[Table1] ([Actor_ID], [Actor_Name], [Movies_ID]) VALUES
(1, N'A1', 2),
(2, N'A2', 1),
(3, N'A3', 3),
(3, N'A3', 4),
(2, N'A2', 6)
INSERT [dbo].[Table2] ([Movies_ID], [Movies_Name]) VALUES
(1, N'M1'),
(2, N'M2'),
(3, N'M3')
(4, N'M4'),
(5, N'M5'),
(6, N'M6')
INSERT [dbo].[Table3] ([Movies_ID], [Revenue_generated]) VALUES
(1, 50),
(2, 100),
(3, 150),
(4, 75),
(5, 120),
(6, 115)
query :
Select
a.Actor_name,
b.Movies_name,
c.Revenue_generated
from
Table1 a
inner join Table2 b on a.Movies_ID = b.Movies_ID
inner join Table3 c on b.Movies_ID = c.Movies_ID
where c.Revenue_generated > 100 AND a.Actor_Name= 'A1'
replace 100 with desired value.
This will help you out.
SELECT
A.Actor-name,B.Movies_name
FROM
table1 A INNER JOIN table2 ON
A.Movies_id= B.Movies_id
INNER JOIN table3 C ON
A.Movies_id= C.Movies_id
WHERE C.Revenue_generated > 10000000000

MySQL GROUP_CONCAT within GROUP_CONCAT different Group By values

I am trying to get a group_concat to work within another group_concat but grouped by different values.
3 Tables Products, Customers , and Product_Customer ( which holds what product each customer bought and what size )
#Creates the Customer Table
CREATE TABLE Customer
(
Cus_Code INT AUTO_INCREMENT PRIMARY KEY,
Cus_Name VARCHAR(20)
);
#Creates the Product Table
CREATE TABLE Product
(
Prod_Code INT AUTO_INCREMENT PRIMARY KEY,
Prod_Name VARCHAR(30)
);
#Creates the Product_Customer Table
CREATE TABLE Product_Customer
(
Cus_Code INT references Customer(Cus_Code),
Prod_Code INT references Product(Prod_Code),
Size INT,
);
Sample Data
#Inserts data into Customer Table
INSERT INTO Customer (Cus_Name)
VALUES
('Aaron')
('Bob')
('Charlie')
#Inserts data into Product Table
INSERT INTO Product (Prod_Name)
VALUES
('A')
('B')
('C')
#Inserts data into Product_Customer Table
INSERT INTO Product_Customer (Cus_Code, Prod_Code, Size)
VALUES
(1, 1, 1),
(1, 1, 2),
(1, 2, 1),
(2, 1, 1),
(2, 2, 1),
(2, 2, 2),
(3, 1, 1),
(3, 2, 1),
(3, 3, 1),
(3, 3, 2)
Desired Output Something like this
Customer Name | Product(Size)
Aaron | A(1,2), B(1)
Bob | A(1), B(1,2)
Charlie | A(1), B(1), C(1,2)
So i need the Size grouped by the product_code , then all that grouped by customer code
I have tried with variations of the following but to no avail
SELECT Customer.Cus_Name, GROUP_CONCAT(DISTINCT Product.Prod_Code, '(', s.list, ')' SEPARATOR ', ') AS 'Products'
FROM Product
JOIN (
SELECT Product.Prod_Code AS id, GROUP_CONCAT(DISTINCT Product_Customer.Size SEPARATOR ',') AS list
FROM Product
INNER JOIN Product_Customer ON Product.Prod_Code = Product_Customer.Prod_Code
GROUP BY id;
) AS s ON s.id = Product_Customer.Prod_Code
INNER JOIN Product_Customer ON Product.Prod_Code = Product_Customer.Prod_Code
INNER JOIN Customer ON Product_Customer.Cus_Code = Customer.Cus_Code
GROUP BY Customer.Cus_Code;
It seems to include all the sizes bought for that product, not what size each customer bought.
Any help would be appreciated
SELECT c.Cus_Name,
GROUP_CONCAT(cncat.Size ORDER BY cncat.Prod_Name SEPARATOR ', ') AS Size
FROM Customer c
INNER JOIN
(
SELECT pc.Cus_Code,
p.Prod_Name,
CONCAT(p.Prod_Name, '(', GROUP_CONCAT(pc.size), ')') Size
FROM Product_Customer pc
INNER JOIN Product p
ON pc.Prod_Code = p.Prod_Code
GROUP BY pc.Cus_Code,
p.Prod_Name
) AS cncat
ON c.Cus_Code = cncat.Cus_Code
GROUP BY c.Cus_Name
SQLFiddle Demo
I think the following version will do what you want:
SELECT c.Cus_Name, ps.prodsizes
FROM Customer c JOIN
(select cus_code, group_concat(prod_code, '(', sizes, ')' separator ', ') as prodsizes
from (select pc.cus_code, pc.prod_code, group_concat(distinct p.size separator ',') as sizes
from Product_Customer pc join
Product p
on pc.prod_code = p.prod_code
group by pc.cus_code, pc.prod_code
) cp
group by cus_code
) ps
on ps.cus_code = c.cus_code
GROUP BY c.Cus_Code;
Note that there are two levels of aggregation to get the products and sizes together, first at the customer product level then at the customer level.
I also introduces table aliases to make the query easier to write and read. There is no need for a distinct at the outer level, because duplicates are combined in the subquery.