Given the following three example tables:
tournament_oc
id_ |
---|
1 |
2 |
match_oc:
id_ | tournament_oc_id |
---|---|
1 | 1 |
2 | 1 |
stat_oc
id_ | tournament_oc_id | value_ |
---|---|---|
1 | 1 | 1 |
2 | 1 | 1 |
3 | 2 | 1 |
I want to sum stat_oc.value_
by tournament_oc.id_
if there are one or more match_oc
records for a given tournament_oc.id_
. The desired output in this case should be:
tournament_oc_id | sum_value |
---|---|
1 | 2 |
I've tried:
SELECT
t.id_ AS tournament_oc_id, sum(s.value_) AS sum_value
FROM
tournament_oc AS t
JOIN
match_oc AS m ON m.tournament_oc_id = t.id_
JOIN
stat_oc as s on s.tournament_oc_id = t.id_
GROUP BY t.id_
However, this returns:
tournament_oc_id | sum_value |
---|---|
1 | 4 |
Presumably because there are two match_oc
records where tournament_oc.id_
== 1.
How would I achieve the desired result?
SQL to replicate tables:
CREATE DATABASE IF NOT EXISTS `test` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `test`;
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE=' 00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
DROP TABLE IF EXISTS `match_oc`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `match_oc` (
`id_` int NOT NULL AUTO_INCREMENT,
`tournament_oc_id` int NOT NULL,
PRIMARY KEY (`id_`),
KEY `fk__match_oc__tournament_oc_id_idx` (`tournament_oc_id`),
CONSTRAINT `fk__match_oc__tournament_oc_id` FOREIGN KEY (`tournament_oc_id`) REFERENCES `tournament_oc` (`id_`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
LOCK TABLES `match_oc` WRITE;
/*!40000 ALTER TABLE `match_oc` DISABLE KEYS */;
INSERT INTO `match_oc` VALUES (1,1),(2,1);
/*!40000 ALTER TABLE `match_oc` ENABLE KEYS */;
UNLOCK TABLES;
DROP TABLE IF EXISTS `stat_oc`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `stat_oc` (
`id_` int NOT NULL AUTO_INCREMENT,
`tournament_oc_id` int NOT NULL,
`value_` tinyint DEFAULT NULL,
PRIMARY KEY (`id_`),
KEY `fk__stat_oc__tournament_oc_id_idx` (`tournament_oc_id`),
CONSTRAINT `fk__stat_oc__tournament_oc_id` FOREIGN KEY (`tournament_oc_id`) REFERENCES `tournament_oc` (`id_`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
LOCK TABLES `stat_oc` WRITE;
/*!40000 ALTER TABLE `stat_oc` DISABLE KEYS */;
INSERT INTO `stat_oc` VALUES (1,1,1),(2,1,1),(3,2,1);
/*!40000 ALTER TABLE `stat_oc` ENABLE KEYS */;
UNLOCK TABLES;
DROP TABLE IF EXISTS `tournament_oc`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tournament_oc` (
`id_` int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id_`)
) ENGINE=InnoDB AUTO_INCREMENT=26193 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
LOCK TABLES `tournament_oc` WRITE;
/*!40000 ALTER TABLE `tournament_oc` DISABLE KEYS */;
INSERT INTO `tournament_oc` VALUES (1),(2);
/*!40000 ALTER TABLE `tournament_oc` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
CodePudding user response:
You can't aggregate on the same level of the JOIN
operation as long as this one is carried out before the aggregation, hence if a tournament has been contested in more than one match, you'll get repeated sum for each contested match (in your case, 2 matches by sum of 2 = 4).
In order to circumvent this problem, you can first filter out tournaments without matches (inside a WHERE
clause), then sum up your tournaments.
SELECT tournament_oc_id,
SUM(value_) AS sum_value
FROM stat_oc
WHERE tournament_oc_id IN (SELECT tournament_oc_id FROM match_oc)
GROUP BY tournament_oc_id
There's no need to use the "tournament_oc" table as long as it is supposed that if a tournament doesn't exist, it should neither appear into the "match_oc" table.
Check the demo here.