简体   繁体   中英

How to count the same field for different times?

I need to extract from my database all the goals scored by a specific player. I have this table design:

MATCH

id | home | away | result | round_id

PLAYER

id | first_name | last_name

GOAL

match_id | player_marker_id | type

GOAL_TYPE

id | description

Essentially the table goal contains all the goals scored in a match , the table bound the field match_id as FK of match.id . The field player_marker_id is a FK of player.id , and goal_type contains all the types that a goal can assume, there is 4 types of status for a goal:

1: first_goal
2: goal
3: pg
4: og

What I need to do is return the top scoring players counting the how many first_goal, goal, pg . I don't need to return og because it corresponds to auto goal.

What I did for now:

$sql = $this->db->prepare("SELECT
p.first_name AS player_first_name,
p.last_name AS player_last_name,
COUNT(*) AS goal_scored,
p.id AS player_id
FROM `match` m
INNER JOIN goal g ON g.match_id = m.id
INNER JOIN player p ON g.player_marker_id = p.id
WHERE m.round_id = :round_id AND g.type != 4
GROUP BY p.id
ORDER BY goal_scored DESC, player_last_name DESC");

This query is working but doesn't return the expected result, infact I get:

{
    "player_first_name": "Ali",
    "player_last_name": "Sowe",
    "goal_scored": "21",
    "player_id": "246638"
},
{
    "player_first_name": "Sindrit",
    "player_last_name": "Guri",
    "goal_scored": "20",
    "player_id": "211786"
},

I would return this output:

 {
    "player_first_name": "Ali",
    "player_last_name": "Sowe",
    "goal_scored": "21",
    "player_id": "246638", 
    "first_goal": "19",
    "goal": "1",
    "pg": "1"
}

I tried also to do this:

$sql = $this->db->prepare("SELECT
p.first_name AS player_first_name,
p.last_name AS player_last_name,
COUNT(*) AS goal_scored,
CASE g.type
  WHEN 1 THEN 'first_goal'
  WHEN 2 THEN 'goal'
  WHEN 3 THEN 'pg'
  WHEN 4 THEN 'og'
END AS goal_type,
p.id AS player_id
FROM `match` m
INNER JOIN goal g ON g.match_id = m.id
INNER JOIN player p ON g.player_marker_id = p.id
WHERE m.round_id = :round_id AND g.type != 4
GROUP BY p.id
ORDER BY goal_scored DESC, player_last_name DESC");

But this will return:

SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #4 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'swp.g.type' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

and I guess isn't the correct way to go.

round_id is the league where the match has played.

You can count only the records of a given goal type by moving the case statement to inside the count aggregate function. Try this:

SELECT
p.first_name AS player_first_name,
p.last_name AS player_last_name,
COUNT(*) AS goal_scored,
COUNT(case when g.type = 1 then 1 else null end) as first_goal,
COUNT(case when g.type = 2 then 1 else null end) as goal,
COUNT(case when g.type = 3 then 1 else null end) as pg,
p.id AS player_id
FROM `match` m
INNER JOIN goal g ON g.match_id = m.id
INNER JOIN player p ON g.player_marker_id = p.id
WHERE m.round_id = :round_id AND g.type != 4
GROUP BY p.id
ORDER BY goal_scored DESC, player_last_name DESC 

Well, if you can't find any better solutions, you can always use TOP (in SQL Server), or LIMIT (in MySQL), to specify the number of results returned. I assume the first record returned in your first solution is the correct one. Here is a link to how to use them https://www.w3schools.com/sql/sql_top.asp

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM