Reputation: 177
Suppose I have the following ouput from my query:
{
"player_first_name": "Albano",
"player_last_name": "Aleksi",
"yellow_cards": "14",
"orange_cards": "0",
"red_cards": "1",
"points": "15",
"player_id": "286635"
}
as you can see the player have 14 yellow cards, 1 red cards and 0 orange cards.
I want calculate the "point" earned by this playern counting each card in the following way:
so the final result should be: 17
I tried to count the total of the points in the following way:
$sql = $this->db->prepare("SELECT
p.first_name AS player_first_name,
p.last_name AS player_last_name,
COUNT(CASE
WHEN c.card_id = 1 THEN 1
END) AS yellow_cards,
COUNT(CASE WHEN c.card_id = 2 THEN 1 END) AS orange_cards,
COUNT(CASE
WHEN c.card_id = 3 THEN 1
END) AS red_cards,
COUNT(CASE
WHEN c.card_id = 1 THEN 1
WHEN c.card_id = 2 THEN 2
WHEN c.card_id = 3 THEN 3
END) AS points,
p.id AS player_id
FROM `match` m
INNER JOIN player_cards c ON c.match_id = m.id
INNER JOIN player p ON c.player_id = p.id
WHERE m.round_id = :round_id
GROUP BY p.id
ORDER BY points DESC, player_last_name ASC");
as you can see I have the following statement:
COUNT(CASE
WHEN c.card_id = 1 THEN 1
WHEN c.card_id = 2 THEN 2
WHEN c.card_id = 3 THEN 3
END) AS points,
the card id correspond the id of the color, so:
why the toal is incorrect?
UPDATE
Expected output:
{
"player_first_name": "Albano",
"player_last_name": "Aleksi",
"yellow_cards": "14",
"orange_cards": "0",
"red_cards": "1",
"points": "17",
"player_id": "286635"
}
as you can see points
is 17
because we have 14 yellow cards (each yellow card is worth 1 point), and we have 1 red card, each red card is worth 3 point, so: 14 + 3 = 17. But I get 15
Upvotes: 0
Views: 2493
Reputation: 424993
The simplest code is:
SUM(c.card_id) AS points,
If you don't want to depend on card_id
having certian values, then this is the next simplest:
SUM((c.card_id = 1) + 2 * (c.card_id = 2) + 3 * (c.card_id = 3))
This works because in MySQL true
is 1
and false
is 0
.
Upvotes: 0
Reputation: 1269603
As mentioned in other answers, count()
counts the number of non-NULL
results. Hence, 0
is as non-NULL
as any other value.
But, MySQL also offers a convenient shortcut that doesn't use CASE
. Boolean expressions are treated as numbers in a numeric context, with "1" for true and "0" for false. So:
SELECT p.first_name AS player_first_name, p.last_name AS player_last_name,
SUM( c.card_id = 1 ) AS yellow_cards,
SUM( c.card_id = 2 ) AS orange_cards,
SUM( c.card_id = 3 ) AS red_cards,
SUM( CASE WHEN c.card_id IN (1, 2, 3) THEN c.card_id ELSE 0 END) AS points,
p.id AS player_id
FROM `match` m INNER JOIN
player_cards c
ON c.match_id = m.id INNER JOIN
player p ON c.player_id = p.id
WHERE m.round_id = :round_id
GROUP BY p.id
ORDER BY points DESC, player_last_name ASC;
If the only allowed card_id
s are 0, 1, 2, and 3, then the points calculation can be simplified to:
SUM( c.card_id ) AS points,
Upvotes: 0
Reputation: 94884
Replace
COUNT(CASE
WHEN c.card_id = 1 THEN 1
WHEN c.card_id = 2 THEN 2
WHEN c.card_id = 3 THEN 3
END) AS points,
with
SUM(CASE
WHEN c.card_id = 1 THEN 1
WHEN c.card_id = 2 THEN 2
WHEN c.card_id = 3 THEN 3
END) AS points,
because with count you just count while you want the sum really. If you count the numbers 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 you get fifteen, if you add them up you get seventeen.
However, there is obviously a card table the card_id
refers to. This card
table should naturally contain the value of the card. So join with the cards table and use
SUM(card.value)
instead of the above.
Upvotes: 2
Reputation: 520998
Since you just want to sum the numerical value of the card to get the total, then just use SUM(card_id)
instead of COUNT
:
SELECT
p.first_name AS player_first_name,
p.last_name AS player_last_name,
COUNT(CASE WHEN c.card_id = 1 THEN 1 END) AS yellow_cards,
COUNT(CASE WHEN c.card_id = 2 THEN 1 END) AS orange_cards,
COUNT(CASE WHEN c.card_id = 3 THEN 1 END) AS red_cards,
SUM(c.card_id) AS points,
p.id AS player_id
FROM match m
INNER JOIN player_cards c
ON c.match_id = m.id
INNER JOIN player p
ON c.player_id = p.id
WHERE
m.round_id = :round_id
GROUP BY
p.id
ORDER BY
points DESC, player_last_name;
Your PHP code should then look like this:
$stmt = $connection->prepare();
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
$red = $row["red_cards"];
$yel = $row["yellow_cards"];
$orange = $row["orange_cards"];
$points = $row["points"];
}
Upvotes: 3
Reputation: 565
What if you try to count the points by query the cards from the database, save it in variables and then count them all without any inline CASE
statements in SQL. Make a simple query where you get each player's red, orange and yellow cards and then count them as in the example.
// The query to get the cards, name etc.
$sql = "SELECT
p.first_name AS player_first_name,
p.last_name AS player_last_name,
c.card_id = 1 THEN 1 AS yellow_cards
c.card_id = 2 THEN 2 AS orange_cards
c.card_id = 3 THEN 3 AS red_cards
p.id AS player_id
FROM `match` m
INNER JOIN player_cards c ON c.match_id = m.id
INNER JOIN player p ON c.player_id = p.id
WHERE m.round_id = round_id
GROUP BY p.id
ORDER BY points DESC, player_last_name ASC";
// Prepared statement to get the cards as variables and then count the points
$stmt = $connection->prepare();
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_assoc()){
$red = $row["red_cards"];
$yel = $row["yellow_cards"];
$orange = $row["orange_cards"];
$points = $red * 3 + $orange * 2 + $yel;
}
Please note that I used prepared statements in the example and the $connection
variable covers the mySQL connection to the server.
Upvotes: 1