I can't get on the right track with this, any help would be appreciated
I have one table
+---+----------+---------+-----------+
|id | match_id | team_id | player_id |
+---+----------+---------+-----------+
| 1 | 9 | 10 | 5 |
| 2 | 9 | 10 | 7 |
| 3 | 9 | 10 | 9 |
| 4 | 9 | 11 | 12 |
| 5 | 9 | 11 | 15 |
| 6 | 9 | 11 | 18 |
+---+----------+---------+-----------+
I want to select these with a where on the match_id and both team id's so the output will be
+---------+-------+------+---------+---------+
| MATCHID | TEAMA | TEAMB| PLAYERA | PLAYERB |
+---------+-------+------+---------+---------+
| 9 | 10 | 11 | 5 | 12 |
| 9 | 10 | 11 | 7 | 15 |
| 9 | 10 | 11 | 9 | 18 |
+---------+-------+------+---------+---------+
It's probably very simple, but i'm stuck..
thanks in advance
p.s. seemed to forgot a column on my first post, sorry
I think you should redesign your table though, maybe the format that you want as output should be your table design.
With your design, it's possible to have three or more teams playing against each other...
So. I gave this another try (coming from Oracle myself, I really miss ROWNUM here).
The following query should give you the result you want to have, but I'm not sure if you should really do that in pure SQL. Maybe you could just combine the teams in your client?
SELECT m1.match_id, m1.team_id, m2.team_id, m1.player_id, m2.player_id
FROM (
SELECT match_id, team_id, player_id,
-- get ranking
( SELECT 1 + count(*)
FROM matches m1b
WHERE m1b.match_id = m1a.match_id
AND m1b.team_id = m1a.team_id
AND m1b.player_id < m1a.player_id) rank
FROM matches m1a
WHERE m1a.team_id = (SELECT MIN(team_id) -- first team
FROM matches
WHERE match_id = m1a.match_id)
) m1,
(
SELECT match_id, team_id, player_id,
-- get ranking
( SELECT 1 + count(*)
FROM matches m2b
WHERE m2b.match_id = m2a.match_id
AND m2b.team_id = m2a.team_id
AND m2b.player_id < m2a.player_id) rank
FROM matches m2a
WHERE m2a.team_id = (SELECT MAX(team_id) -- second team
FROM matches
WHERE match_id = m2a.match_id)
) m2
WHERE m1.match_id = m2.match_id
AND m1.rank = m2.rank
What I do here is:
Select all ROWs from the teams with lower team_id per match and give them a ranking (1 to 3 per match)
Select all ROWs from the teams with higher team_id per match and give them a ranking (1 to 3 per match)
Combine those two queries in one result, where the match_id and the ranking match
match is a reserve word in mysql. table name used here is matchs
select match_id, sum(if(id=1, team_id,0))team_A, sum(if(id=2,team_id,0)) team_b
from matchs
group by match_id;
+----------+--------+--------+
| match_id | team_A | team_b |
+----------+--------+--------+
| 5 | 9 | 10 |
+----------+--------+--------+
1 row in set (0.00 sec)
I'm not sure if the previous answers will give you what you're looking for, at least I took your question to mean something else - perhaps you could clarify the purpose of the table and the query. If the table associates teams with matches and you want a query to show you all the teams associated with one match, then your query should be
select team_id as teams from table where match_id = id_here
which would give you back (for id_here being 5)
teams
-----
9
10
Take a look at the url below, It is exactly what you want but is in t-sql. It can merge any number of rows.
Converting fields into columns
Related
Maybe this question is super specific but I can't really find a way to do it.
A bit of background. I'm studying, and In order to learn this I'm playing around counting stats from our Wednesday football matches with my friends.
Now in order to make data as normalized as possible and calculate everything programmatically, I have a table called matches and a table called goals.
Matches
+----+------------+
| id | date |
+----+------------+
| 1 | 05-01-2022 |
+----+------------+
| 2 | 12-01-2022 |
+----+------------+
Goals
+----+--------------+
| id | match | team |
+----+--------------+
| 1 | 1 | A |
+----+--------------+
| 2 | 1 | B |
+----+--------------+
| 3 | 1 | B |
+----+--------------+
| 4 | 2 | A |
+----+--------------+
| 5 | 2 | A |
+----+--------------+
So my objective here is to count the goals for each team in each match, compare both values to determine the winner and come up with a result like this:
Results
+-------+------------+
| match | result |
+-------+------------+
| 1 | B |
+-------+------------+
| 2 | A |
+-------+------------+
I'm currently doing this fairly straightforward using laravel on my app, but I'm trying to get it done through SQL queries only.
I also know that this would be much easier, if i simply added a goals_team_a, goals_team_b, result columns to my Matches table. If this is the actual correct solution is super easy to add, I just though at some point goals may differ from the score because of a typo or something and this is the way to be extra sure. Probably an overkill
The current structure of matches and goals is definitely flawed. If a given match id has no goals scored by either side there is no record of who played. By simply adding home and away teams to the match you have a more meaningful match entity and it becomes simple to query for the result.
Matches
id
kick_off
home_team_id
away_team_id
1
2022-01-05 10:00:00
1
2
2
2022-01-12 14:30:00
2
1
Teams
id
name
1
A
2
B
Additionally, if your goals table is as simple as suggested, it serves no purpose but I suspect this was simplification for the sake of providing an example. Assuming there is a player and time goal scored as part of the goal table, it has obvious value.
Goals
id
match_id
team_id
player_id
time_scored
1
1
1
1
10:01:23
2
1
2
2
10:17:38
3
1
2
2
11:02:44
4
2
1
1
15:42:53
5
2
1
1
15:47:18
With the teams identified in the match you can then use something like -
select m.id as match_id,
case
when count(distinct hg.id) > count(distinct ag.id) then ht.name
when count(distinct hg.id) < count(distinct ag.id) then at.name
else 'draw'
end as `result`
from matches m
join teams ht on m.home_team_id = ht.id
join teams at on m.away_team_id = at.id
left join goals hg on m.home_team_id = hg.team_id and m.id = hg.match_id
left join goals ag on m.away_team_id = ag.team_id and m.id = ag.match_id
group by m.id
to get -
match
result
1
B
2
A
Here's a db<>fiddle to play around with.
I'm sorry for fuzzy title of this question.
I have 2 Tables in my database and want to count records of first_table using "group by" on a foreign key id that exists in a column of second_table (which stores ids like array "1,2,3,4,5").
id | name | fk_id
1 | john | 1
2 | mike | 1
3 | jane | 2
4 | tailor | 1
5 | jane | 3
6 | tailor | 5
7 | jane | 4
8 | tailor | 5
9 | jane | 5
10 | tailor | 5
id | name | fk_ids | s_fk_id
1 | xxx | 1,5,6 | 1
2 | yyy | 2,3 | 1
3 | zzz | 9 | 1
4 | www | 7,8 | 1
Now i wrote the following query but it not working properly and displays wrong numbers.
I WANT TO:
1-Count records in first_table group by "fk_id"
2-Sum the counted records which exists in "fk_ids"
3-Display the sum result (sum of related counts) grouped by id.
symbol ' ' means ``.
select sum(if(FIND_IN_SET('fk_id', 'fk_ids')>0,'count',0) 'sum', 'count', 'from'.'fk_id', 'second_table'.* FROM 'second_table'
LEFT JOIN
(
SELECT 'fk_id', count(*) 'count'
FROM 'first_table'
group BY 'fk_id'
) AS 'from'
ON FIND_IN_SET('fk_id', 'fk_ids')>0
WHERE 'second_table'.'s_fk_id'=1
GROUP BY 'id'
ORDER by 'count' DESC
This table has many data and we have no plan to change the structure.
Edit:
Desired output:
id | name | sum
1 | xxx | 7 (3+4+0)
2 | yyy | 2 (1+1)
3 | zzz | 0 (0)
4 | www | 0 (0+0)
After two holidays i came back to work and found out that the "FIND_IN_SET" function is not working properly with space contained string.
And the problem is that i was ignored the spaces too, (same as this question)
Finnaly this query worked:
select sum(`count`) `sum`, `count`, `from`.`fk_id`, `second_table`.* FROM `second_table`
LEFT JOIN
(
SELECT `fk_id`, count(*) `count`
FROM `first_table`
group BY `fk_id`
) AS `from`
ON FIND_IN_SET(`fk_id`, replace(`fk_ids`,' ',''))>0
WHERE `second_table`.`s_fk_id`=1
GROUP BY `id`
ORDER by `count` DESC
And the magic is replace(fk_ids,' ','')
I realize this question has been asked quite a few times, however i haven't managed to find a working solution for my case.
Essentially my problem arises because MySQL Doesn't allow sub-querys in views.
I found a few workarounds but they don't seem to work.
In more detail...
My first table (competitions) stores a users competitions:
id_tournament | id_competition | id_user | result
-------------------------------------------------
1 | 1 | 1 | 10
1 | 1 | 2 | 30
1 | 2 | 1 | 20
1 | 2 | 3 | 50
1 | 3 | 2 | 90
1 | 3 | 3 | 100
1 | 3 | 4 | 85
In this example there are three competitions:
(
user1 vs. user2,
user1 vs. user3,
user2 vs. user3 vs. user4
)
My problem is that i need to define a view that gives me the winners in each competition.
Expected Result:
id_tournament | id_competition | id_winner
------------------------------------------
1 | 1 | 2
1 | 2 | 3
1 | 3 | 3
This can be solved with the query:
SELECT
id_tournament,
id_competition,
id_user as id_winner
FROM (
SELECT * FROM competitions ORDER BY result DESC
) x GROUP BY id_tournament, id_competition
This query however uses a subquery (not allowed in views), so my first solution was to define a 'helper view'as :
CREATE VIEW competitions_helper AS (
SELECT * FROM competitions ORDER BY result DESC
);
CREATE VIEW competition_winners AS (
SELECT
id_tournament,
id as id_competition,
id_user as winner
FROM competitions_helper GROUP BY id_tournament, id_competition
);
However this does not seem to give the correct result.
It's result will then be:
id_tournament | id_competition | id_winner
------------------------------------------
1 | 1 | 1
1 | 2 | 1
1 | 3 | 1
What i don't understand is why it works when i use Sub-querys and why it gives a different result with the exact same statement in a view.
Any help is appreciated, thanks alot.
This is due to the GROUP BY behaviour.
In this case, the server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate, which is probably not what you want.
I would solve the problem in this way:
CREATE VIEW competitions_helper AS (
SELECT id_tournament,
id_competition,
MAX(result) as winning_result
FROM competitions
GROUP BY id_tournament,
id_competition
);
CREATE VIEW competition_winners AS (
SELECT c.id_tournament,
c.id_competition,
c.id_user
FROM competitions c
INNER JOIN competitions_helper ch
ON ch.id_tournament = c.id_tournament
AND ch.id_competition = c.id_competition
AND ch.winning_result = c.result
);
If I have a table with the following structure and data:
id | user_id | created_at
-------------------------
1 | 7 | 0091942
2 | 3 | 0000014
3 | 6 | 0000890
4 | 6 | 0029249
5 | 7 | 0000049
6 | 3 | 0005440
7 | 9 | 0010108
What query would I use to get the following results (explanation to follow):
id | user_id | created_at
-------------------------
1 | 7 | 0091942
6 | 3 | 0005440
4 | 6 | 0029249
7 | 9 | 0010108
As you can see:
Only one row per user_id is returned.
The row with the highest created_at is the one returned.
Is there a way to accomplish this without using subqueries? Is there a name in relational algebra parlance that this procedure goes by?
The query is known as a groupwise maximum, which (in MySQL, at least) can be implemented with a subquery. For example:
SELECT my_table.* FROM my_table NATURAL JOIN (
SELECT user_id, MAX(created_at) created_at
FROM my_table
GROUP BY user_id
) t
See it on sqlfiddle.
You can just get the max and group by the user_id:
select id,user_id,max(created_at)
from supportContacts
group by user_id
order by id;
Here is what it outputs:
ID USER_ID MAX(CREATED_AT)
1 7 91942
2 3 5440
3 6 29249
7 9 10108
See the working demo here
Note that the example on the fiddle uses the created_at field as int, just use your format it should make no difference.
EDIT: I will leave this answer as a referece but note that his query will produce undesired results as Gordon stated, please do not use this in production.
I have a question regarding performance of the MySQL DBMS.
Perhaps a trivial matter.
There are two tables and I need to get result as below :
PLAYERS VISITS
ID | PLAYER_NAME ID | PLAYER_ID | SEEN
---------------- ---------------------------
1 | user 1 1 | 2 | 2012-12-12
2 | user 2 2 | 2 | 2012-12-13
3 | user 3 3 | 3 | 2012-12-13
4 | user 4 4 | 3 | 2012-12-14
5 | 3 | 2012-12-14
6 | 2 | 2012-12-15
RESULT:
ID | PLAYER_NAME | LAST_SEEN
----------------------------
1 | user 1 | NULL / 'NEVER'
2 | user 2 | 2012-12-15
3 | user 3 | 2012-12-14
4 | user 4 | NULL / 'NEVER'
My current query is :
SELECT
players.id,
players.player_name,
MAX(visits.seen) AS last_seen
FROM players
LEFT JOIN visits ON players.id = visits.player_id
GROUP BY players.id,players.player_name
Works for me but it seems to me that it should be a more efficient method.
It's just key part of a larger query.
Thomas
To make this join efficient there has to be an index on player_id in VISITS. Look into
`CREATE INDEX`
here.
To check the query efficiency you can always use:
EXPLAIN SELECT /* your select here */
Also if PLAYERS.ID is unique and primary key it's perfectly fine to group only by this id.
SELECT
players.id,
players.player_name,
MAX(visits.seen) AS last_seen
FROM players
LEFT JOIN visits ON players.id = visits.player_id
GROUP BY players.id
but your original query is perfectly fine. Make sure you fully understand GROUP BY and the consequences for columns not included in GROUP BY if you omit columns. This can have unintended consequences in other queries (where the same id doesn't mean the same name i.e.)