Create MYSQL Table Counting Multiple Categories for Names - mysql

I have two tables, an Events table and a Category table. The data would look something like this (simplified as I omitted dates):
Events:
Name | catid
John 35
Mary 36
Ed 37
John 38
Tom 39
Mary 40
Category:
catid | category
35 run
35 swim
36 bike
36 swim
36 run
37 bike
38 swim
39 swim
40 run
If you think of each row in the events table as another day we have a person and one or more activities that person performed in the day. Let's say on Sunday John participated in running and swimming the 'catid' in the Events table references the two activities in the Category table.
What I am looking to do is get a table with distinct names and a count of each activity they performed over time. Like this:
Name | run | swim |bike
Ed 1
John 1 2
Mary 1 1
Tom 1
I know I would probably need some JOIN commands but I am not sure how to setup the SQL statement.

Try something like this
SELECT
e.Name,
SUM(CASE WHEN c.Category = 'run' THEN 1 ELSE 0 END) as run,
SUM(CASE WHEN c.Category = 'swim' THEN 1 ELSE 0 END) as swim,
SUM(CASE WHEN c.Category = 'bike' THEN 1 ELSE 0 END) as bike
FROM Events as e
LEFT JOIN Category as c ON c.catid = e.catid
GROUP BY e.Name, e.catid
EDIT: I did not notice that there were 2 Johns in your data set. I have modified the query to fix that. I am also adding a SQL Fiddle to show the changes.
SQL FIDDLE
EDIT2: Query using With ROLL UP with totals row is shown in FIDDLE 2

I think you have some issues with the structure of your database and data therein. If you have a table of categories you should not have catid be repeated for different category names. Might be helpful to get a better handle on the actual structure of the database if you include your code for creating the tables in question.

Related

SQL - Can't figure out how to join three tables

I have four tables like this:
**USERS**
___________________________
user_ID username password
---------------------------
1 user1 1234
2 user2 5678
**TEAMS**
______________________________________
team_ID formation team_name user_ID
--------------------------------------
1 4-4-2 team1 1
2 4-3-3 team2 2
**PLAYERS**
____________________________________
player_ID name position rating
------------------------------------
1 Ronaldo LW 94
2 Messi RW 93
3 Hazard LW 90
**ACTIVE PLAYERS**
___________________________________
ID player_ID team_ID cardview_ID
-----------------------------------
1 1 2 9
2 3 1 7
3 2 1 3
Each user has a team with a formation and a team name. The "active players" tables references the player_ID with the team_ID to see which players are currently active on which teams.
Let's say that user1 logs in to the application, then I want to get all the players name, ratingand their cardview_ID. Something that should look like this:
_____________________________
name rating cardview_ID
-----------------------------
Hazard 90 7
Messi 94 3
These are the players that are currently active on user1's team which is team1.
How can I get this joined table? I have tried with an inner join but that didn't seem to do the work for me.
_______________________________ EDIT_____________________________________
This is the query that doesn't give the desired result:
SELECT players.name, players.rating, activeplayers.cardview_ID
FROM players
INNER JOIN
activeplayers
ON players.player_ID = usedplayers.player_ID
I also tried to join them on team_ID.
Assuming you have the logged in user's ID available, I think this will give you what you're asking for:
SELECT
[PLAYERS].name,
[PLAYERS].rating,
[ACTIVE PLAYERS].cardview_ID
FROM [TEAMS]
JOIN [ACTIVE PLAYERS]
ON [TEAMS].team_ID = [ACTIVE PLAYERS].team_id
JOIN [PLAYERS]
ON [PLAYERS].player_id = [ACTIVE PLAYERS].player_id
WHERE [TEAMS].user_id = <logged_in_user_id>
Please also note the questions asking for clarifying details, and also feel free to respond if this query gets you part of the way but you need more information. The content in angle brackets are of course a placeholder. I also don't know your exact table names so you may need to replace what is in the square brackets with the actual table names.
Assuming that the query in your post contains a typo and is actually this:
SELECT players.name, players.rating, activeplayers.cardview_ID
FROM players
INNER JOIN
activeplayers
ON players.player_ID = activeplayers.player_ID
This query will correctly return all the players who are active players. Now to limit it only to the team for User1, you need to add an additional join to the Teams table, same way you did the join above, and then add a WHERE clause that filters on the Teams.UserID.
That's it.

Querying table with dates in SQL

I need to query a MySQL database table that looks like this:
Bike Owner Date
-----------------------
1 Oscar 2014-02-02
2 Oscar 2014-02-02
3 John 2014-04-28
4 Jane 2014-05-29
2 John 2015-04-16
3 Mike 2015-06-16
1 Bob 2015-07-16
4 John 2015-08-16
2 Mike 2016-04-16
3 John 2016-04-16
It contains 4 bikes and as soon as the bike switches from owner, a new record is placed within this table. Since this table doesn't have an 'until' attribute, I am stuck creating a query that gets all the owners of all bikes at a specific date, say 2015-07-06.
Does anyone now how to do this in an easy way? I can think of ways of doing this by creating functions or temporary tables, but this seems way too far fetched for such an easy question.
Thanks!
One method uses an explicit join and aggregation:
select b.*
from (select bike, max(date) as maxdate
from bikes b
where date <= '2015-07-06
group by bike
) bd join
bikes b
on b.bike = bd.bike and b.date = bd.maxdate;
A somewhat shorter way to write this:
select b.*
from bikes b
where b.date = (select max(b2.date) from bikes b2 where b2.bike = b.bike);
If I understood your requirement correctly then it is very straight foreword query, getting all owner of bike on specific date
select b.*
from bikes b
where CAST(b.date AS DATE) = '2015-07-06'

Sql show top 10 requested products of every group

I have the following data stored in my database.
I want to know what the 10 most searched parts are for every car.
Below I made an example of the data that is stored in the database.
One table contains the names of the cars with the car id.One table contains the requests with one or more request id('s) for every car.One table contains the request id with the name of the requested part.
Table cars
audi (7)
bmw (12)
Table request
7 (100)
7 (234)
7 (367)
7 (562)
7 (729)
7 (765)
7 (881)
Table request_parts
100 (achterband)
234 (voorband)
367 (motor)
562 (accu)
729 (achterband)
765 (kopeling)
881 (koeling)
What the query should return is something like this, as in the example 'achterband' was found twice
audi achterband 2
audi voorband 1
audi motor 1
audi accu 1
audi kopeling 1
The query that I currently have counts how often the part 'motor' has been requested for every car. however I can't find out how to do this not just for one product but for all of them at the same time. right now its not important to have the name of the car as the id is already shown.
SELECT COUNT(*), requests.sibben_brand_id, request_parts.name
FROM request_parts
JOIN requests ON requests.id = request_parts.request_id
WHERE requests.sibben_brand_id IS NOT NULL
AND request_parts.name LIKE 'motor'
GROUP BY requests.sibben_brand_id
ORDER BY COUNT(*) DESC `
Does any one has a idea how i could get the correct data?
try with this:
SELECT COUNT(*), requests.sibben_brand_id, request_parts.name
FROM request_parts
JOIN requests ON requests.id = request_parts.request_id
WHERE requests.sibben_brand_id IS NOT NULL
GROUP BY requests.sibben_brand_id,request_parts.name
ORDER BY COUNT(*) DESC `
with
cars table as (id,name)
request table as (id,car_id,request_id)
request_parts table as (id,request_id,part_name)`
the following query returns top 10 records
select top 10 c.name, rqp.part_name,count(*) as repetition
from request as r, request_parts as rqp, cars as c
where rqp.request_id = r.request_id AND r.car_id = c.Id
group by rqp.part_name,c.name
order by repetition desc`

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

MySQL Join Multiple (More than 2) Tables with Conditions

Assume I have 4 tables:
Table 1: Task
ID Task Schedule
1 Cut Grass Mon
2 Sweep Floor Fri
3 Wash Dishes Fri
Table 2: Assigned
ID TaskID (FK) PersonID (FK)
1 1 1
2 1 2
3 2 3
4 3 2
Table 3: Person
ID Name
1 Tom
2 Dick
3 Harry
Table 4: Mobile
ID PersonID (FK) CountryCode MobileNumber
1 1 1 555-555-5555
2 2 44 555-555-1234
3 3 81 555-555-5678
4 3 81 555-555-0000
I'm trying to display the
Task on a certain day
Name of person assigned to task
Phone numbers of said person
I think it should be something like the following, but I'm not sure how to set up the conditions so that the results are limited correctly:
SELECT T.ID, T.Task, P.Name, M.MobileNumber
FROM Task AS T
LEFT JOIN Assigned AS A
ON T.ID = A.TaskID
LEFT JOIN Person AS P
ON A.PersonID = P.ID
LEFT JOIN Mobile AS M
ON M.PersonID = P.ID
WHERE T.Schedule = Fri
My goal is to fetch the following information (it will be displayed differently):
Tasks Name MobileNumber
Sweep Floor, Wash Dishes Dick, Harry 44-555-555-1234, 81-555-555-5678, 81-555-555-0000
Of course, if JOIN is the wrong way to do this, please say so.
It's unclear what you want to do with duplicate data in this case, but you should be looking at using inner joins instead of outer joins, and using something like group_concat() to combine the phone numbers.