Joining 5 tables with parent child relation in SQL - mysql

I am working on a query with a join of 5 tables, and also there is parent child relation.
I am trying to query university sales and this is my query. I am struggling to get total sales of university. How should I query this?
I attached category table and invoice table.
Select invoice.id, invoice.total, categories.type, categories.name
FROM invoices
Join sales on sales.invoice_id = invoices.id
Join course on course.id = sales.course_id
Join category_subject on category_subject.subject_id = course.subject_id
Join categories on categories.id = category_subject.category_id
categories table with parent-child relationship.
Here is the categories table:
id
parent_id
name
type
1
null
England
country
2
null
France
country
3
16
A university
university
4
17
B university
university
5
16
C university
university
6
17
D university
university
7
1
E high school
stage
8
2
F high school
stage
9
3
computer engineering
department
10
4
art
department
11
5
chemistry
department
12
7
grade 9
grade
13
7
grade 10
grade
14
8
grade 11
grade
15
8
grade 12
grade
16
1
England- university
stage
17
2
France-university
stage
18
6
business
department
and this is invoice table:
id
total
1
50
2
100
3
350
4
850
5
65
6
75
7
850
8
650
9
250
10
450
11
300
12
100
13
450
14
950
15
350
16
750
17
320

There's not currently enough information included the in the question to really answer it, but start with this and tell us what you're still missing:
SELECT i.id, i.total, ct.type, ct.name
FROM invoices i
INNER JOIN sales s on s.invoice_id = i.id
INNER JOIN course c on c.id = s.course_id
INNER JOIN category_subject cs on cs.subject_id = c.subject_id
INNER JOIN categories ct on ct.id = cs.category_id
WHERE ct.type = 'University'
Additionally, from what I've inferred you want include all invoices for category IDs 3, 4, 5, and 6 -- which are directly Universities -- as well as 9, 10, 11, and 18 -- which are children of the Universities.
This is easy enough to do if you know you only have one level like this. One additional join + a coalesce() in the WHERE clause can do the job, as could a UNION to a similar query. But if you could have arbitrarily more levels the query becomes much trickier; you must use a recursive CTE to check the whole category tree. Also, right now the sample data never shows a University with a parent category. If the actual data allows for this that adds another wrinkle. So again: not enough information in the question to provide a good answer at this time.

Related

How to count rows in mysql subquery

I have two tables course and registered_course
course table
crid
crname
crlevel
1
math
senior
2
english
senior
3
physics
senior
Registered course table
id
crid
student_id
1
2
25
2
2
26
3
3
23
4
3
24
5
3
27
so i want to achieved this result the first table join with second table and a count of students that registered a subject just like below thanks
crname
crlevel
number_of_student
math
senior
2
physic
senior
3
SELECT table1.crname, table1.crlevel, count(table2.studentid)
FROM table1
INNER JOIN table2 ON table1.crid = table2.crid
GROUP BY table1.crname, table1.crlevel

Duplicated values using INNER JOIN in mysql

i have 3 tables, i want to get the total sum, but im not getting the right results.
First table(investors)
id investor_id
1 27
2 27
3 29
4 30
5 31
Second table(payments)
id investor_id
1 27
2 27
3 28
4 29
5 30
6 31
7 27
Third table(billed)
id payments_id billed
1 1 189
2 2 300
3 3 500
4 4 700
5 5 200
6 6 300
HERE is my query
SELECT SUM(billed.billed)
FROM billed AS billed
INNER JOIN payments AS payments ON billed.payments_id = payments.id
INNER JOIN investors AS investors ON payments.investor_id = investors.investor_id
instead of getting 1689 only, im getting a results of 2178
i am really stuck with my answer is there really a way to do this just by using query only?
If you just want the total sum for bills, just query that table directly, no need to join:
SELECT SUM(billed) FROM billed
If for some reason you need to JOIN, the I select the distinct investors in a subquery, then join it:
SELECT SUM(billed.billed)
FROM billed AS billed
INNER JOIN payments AS payments ON billed.payments_id = payments.id
INNER JOIN (SELECT DISCTINCT investors FROM investors) AS investors ON payments.investor_id = investors.investor_id

MySQL query table filtering issue

I've been struggling on the following.
I have 3 tables: players, players_clothes, and teams_clothes.
Table players:
id user team_id
1 tom 4
2 robo 5
3 bob 4
So tom and bob are both on the same team
Table players_clothes:
id clothes_id p_id
1 13 1
2 35 3
3 45 3
Bob has clothing article 35 and 45, robo has none.
Table teams_clothes:
id clothes_id team_id
1 35 4
2 45 4
3 55 4
4 65 5
This shows which teams have rights to which articles of clothing. The problem: tom is wearing an article of clothing that does no belong to his team... Let's assume this is illegal.
I'm having trouble figuring out how to capture all those who are wearing illegal clothes for a particular team.
SELECT pc.clothes_id FROM players AS p
JOIN players_clothes AS pc
ON p.id = pc.p_id
AND p.team_id = 4 GROUP BY pc.clothes_id
(I group by players_clothes.clothes_id because believe it or not, two players can be assigned the same piece of clothing)
I think this results the following set (13, 35, 45)
Now I would like to check against the actual set of clothes that team 4 owns.
SELECT clothes_id FROM teams_clothes WHERE team_id = 4 and this return (35, 45, 55)
How can I create a query so that it returns (13)? I've tried things like NOT EXISTS IN but I think the GROUP BY players_clothes.clothes_id part gets in the way
I suggest
select * from A where team_id = $team_id join B on B.a_id = A.id
where not exists
(
select 1 from C where C.clothes_id = B.clothes_id and team_id = $team_id
)
Basically, we find all As who are on their team and for each A join to all clothing they wear, and then only return the row IF we can't find indication in table C that the clothing is on our team (this covers not existent in C and exists but in the wrong team on C)
This should do the trick:
SELECT b.a_id, b.clothes_id
FROM
b INNER JOIN a
ON b.a_id = a.id
LEFT OUTER JOIN c
ON a.team_id = c.team_id
WHERE
c.clothes_id = NULL
The thought is to do an outer join on the combination of tables A/B against table C. And then only look for the cases where c.clothes_id is NULL, which would represent those cases where there is no relational match on the outer join (i.e. the clothes item is not approved for that user's team).
Not sure if this is too late for you, but I'd change the database model itself to make this situation impossible in the first place:
("Unimportant" fields omitted for brevity, including surrogate keys such as PLAYER_ID.)
Note how TEAM_ID migrates through the identifying relationship from TEAM to PLAYER, and then to the PLAYER_ARTICLE, where it merges with the same field migrated through the TEAM_ARTICLE. Since there is only one physical TEAM_ID field in the PLAYER_ARTICLE table, you can never insert a row that would reference different teams.
To put it in more abstract terms: this is a diamond-shaped dependency, where TEAM is at the top and PLAYER_ARTICLE at the bottom of the diamond. The merger at the bottom (enabled by the usage of identifying relationships) ensures sides must always point to the same top.
Your example data would be represented like this...
PLAYER:
TEAM_ID PLAYER_NO
4 1 -- Tom
5 1 -- Robo
4 2 -- Bob
TEAM_ATRICLE:
TEAM_ID ARTICLE_ID
4 35
4 45
4 55
5 65
PLAYER_ARTICLE:
TEAM_ID PLAYER_NO ATRICLE_ID
4 1 13 -- Tom: this is impossible (FK violation).
4 2 35 -- Bob
4 2 45 -- Bob

having trouble writing a query that list all salesmen that did not sell to a particular customer

I was successful in writing the query that lists salesmen that did sell to a particular customer, but not those that have not. I suspect it is because the same salesmen that sold to the specific customer, also sold to other customers.
select a.name from salesperson a inner join orders b on
a.salesperson_id = b.salesperson_id where cust_id="4";
I was thinking that modifying the same query like this would do the trick:
.... a.salesperson_id <> b.salesperson_id where cust_id="4";
But the result lists all the salesmen. This is most likely due to the fact that the same salesmen that were returned in the original query, also sold to other customers
The 3 tables look like this:
Salesperson table
salesperson_ID, Name, Age, Salary
1 Abe 61 140000
2 Bob 34 44000
5 Chris 34 40000
7 Dan 41 52000
8 Ken 57 115000
11 Joe 38 38000
Customer table
cust_ID, Name, City Industry Type
4 faralon sacramento H
6 Apple cupertino S
7 Honda NY B
9 Kolb Oshkosh B
Orders table
Number, Order_date, cust_id, salesperson_id, Amount
10 8/2/1996 4 2 540
20 1/30/1999 4 8 1800
30 7/14/1995 9 1 460
40 1/29/1998 7 2 2400
50 2/3/1998 6 7 600
60 3/2/1998 6 7 720
70 5/6/1998 9 7 150
Any help would be greatly appreciated. ~Alpinehyker
You can do something like this:
select a.name from salesperson a
left join orders b on a.salesperson_id = b.salesperson_id and b.cust_id="4"
where b.Number is null
So, get all salepersons, left join to orders for customer 4, and return only rows where there is no such order.
I am assuming that Number is the primary key for Orders, or at least not null.
All salespeople who have NOT sold to customer_ID 4:
SELECT s.Name FROM Salesperson AS s
LEFT JOIN Orders AS o
ON s.salesperson_ID = o.salesperson_ID
WHERE o.customer_ID <> 4
GROUP BY o.salesperson_ID;
Perhaps this will work
SELECT
s.*
FROM `Salesperson` AS s
LEFT JOIN `Orders` AS o ON o.`salesperson_id` = s.`salesperson_ID`
WHERE
o.`cust_id` NOT IN (4)
GROUP BY s.`salesperson_ID`;
Answer to your 2nd question:
SELECT
COUNT(*) AS num_of_orders
,s.`Name`
FROM `Salesperson` AS s
LEFT JOIN `Orders` AS o ON o.`salesperson_id` = s.`salesperson_ID`
GROUP BY s.`salesperson_ID`
HAVING num_of_orders >= 2;
...and 3rd question. (assuming you have your highAchiever table ready)
INSERT INTO `highAchiever`
(`Name`,`Age`)
SELECT
`Name`
,`Age`
FROM `Salesperson`
WHERE
`Salary` >= 100000;

Order by on a group sum criteria

Is it possible to order return rows with a criteria on a sum group ?
For example, my data are :
Id Price Product Category
1 12 Book1 Car
2 1 Book2 Art
3 8 Book3 Car
4 7 Book4 Art
5 11 Book5 Car
6 24 Book6 Bridge
As the sum of Car books is 31, the sum of Art books is 8 and the sum of Bridge books is 24, I would like to have the following result (Car first, then Bridge and then Art):
Id Price Product Category
1 12 Book1 Car
3 8 Book3 Car
5 11 Book5 Car
6 24 Book6 Bridge
2 1 Book2 Art
4 7 Book4 Art
On the other hand, I would like to add other Order by criteria (in the example, "Product" criteria).
I have tried many things using ORDER BY and GROUP BY but it always aggregate my results.
Thanks for help !
You could do something like this:
select
l.* from table l
inner join (
select category, sum(price) as total from table group by category
) r
on l.category = r.category
order by r.total, <some_other_column>
This is the procedure I followed:
find the subtotals
join the original table to the subtotals
order the original table by those subtotals