Description:
Run the script from the "How to repeat" section.
Then run the following query, that works as expected:
SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`
FROM `LocustLeaders` AS `l`
CROSS JOIN (
SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`
FROM `Gears` AS `g`
) AS `t`
ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`;
The following result is correct:
+------------+---------+------------------+--------------+----------------+---------------+------+
| Nickname | SquadId | AssignedCityName | HasSoulPatch | LeaderNickname | LeaderSquadId | Rank |
+------------+---------+------------------+--------------+----------------+---------------+------+
| Baird | 1 | Jacinto | 1 | Marcus | 1 | 2 |
| Baird | 1 | Jacinto | 1 | Marcus | 1 | 2 |
| Baird | 1 | Jacinto | 1 | Marcus | 1 | 2 |
| Baird | 1 | Jacinto | 1 | Marcus | 1 | 2 |
| Baird | 1 | Jacinto | 1 | Marcus | 1 | 2 |
| Baird | 1 | Jacinto | 1 | Marcus | 1 | 2 |
| Cole Train | 1 | Jacinto | 0 | Marcus | 1 | 1 |
| Cole Train | 1 | Jacinto | 0 | Marcus | 1 | 1 |
| Cole Train | 1 | Jacinto | 0 | Marcus | 1 | 1 |
| Cole Train | 1 | Jacinto | 0 | Marcus | 1 | 1 |
| Cole Train | 1 | Jacinto | 0 | Marcus | 1 | 1 |
| Cole Train | 1 | Jacinto | 0 | Marcus | 1 | 1 |
| Dom | 1 | Ephyra | 0 | Marcus | 1 | 2 |
| Dom | 1 | Ephyra | 0 | Marcus | 1 | 2 |
| Dom | 1 | Ephyra | 0 | Marcus | 1 | 2 |
| Dom | 1 | Ephyra | 0 | Marcus | 1 | 2 |
| Dom | 1 | Ephyra | 0 | Marcus | 1 | 2 |
| Dom | 1 | Ephyra | 0 | Marcus | 1 | 2 |
| Marcus | 1 | NULL | 1 | NULL | 0 | 4 |
| Marcus | 1 | NULL | 1 | NULL | 0 | 4 |
| Marcus | 1 | NULL | 1 | NULL | 0 | 4 |
| Marcus | 1 | NULL | 1 | NULL | 0 | 4 |
| Marcus | 1 | NULL | 1 | NULL | 0 | 4 |
| Marcus | 1 | NULL | 1 | NULL | 0 | 4 |
| Paduk | 2 | Unknown | 0 | Baird | 1 | 1 |
| Paduk | 2 | Unknown | 0 | Baird | 1 | 1 |
| Paduk | 2 | Unknown | 0 | Baird | 1 | 1 |
| Paduk | 2 | Unknown | 0 | Baird | 1 | 1 |
| Paduk | 2 | Unknown | 0 | Baird | 1 | 1 |
| Paduk | 2 | Unknown | 0 | Baird | 1 | 1 |
+------------+---------+------------------+--------------+----------------+---------------+------+
30 rows in set (0.00 sec)
Now run the following query, that is semantically equal to the previous query:
SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`
FROM `LocustLeaders` AS `l`
CROSS JOIN LATERAL (
SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`
FROM `Gears` AS `g`
WHERE EXISTS (
SELECT 1
FROM `LocustLeaders` AS `l0`
WHERE (`l0`.`ThreatLevelNullableByte` = `l`.`ThreatLevelNullableByte`) OR (`l0`.`ThreatLevelNullableByte` IS NULL AND `l`.`ThreatLevelNullableByte` IS NULL))
) AS `t`
ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`;
Because both queries are semantically equal, they should both return the same results set. However, this second query leads to a completely different result, which is incorrect and unexpected:
+------------+---------+------------------+--------------+----------------+---------------+------+
| Nickname | SquadId | AssignedCityName | HasSoulPatch | LeaderNickname | LeaderSquadId | Rank |
+------------+---------+------------------+--------------+----------------+---------------+------+
| Baird | 1 | Jacinto | 1 | Marcus | 1 | 2 |
| Baird | 1 | Jacinto | 1 | Marcus | 1 | 2 |
| Cole Train | 1 | Jacinto | 0 | Marcus | 1 | 1 |
| Cole Train | 1 | Jacinto | 0 | Marcus | 1 | 1 |
| Dom | 1 | Ephyra | 0 | Marcus | 1 | 2 |
| Dom | 1 | Ephyra | 0 | Marcus | 1 | 2 |
| Marcus | 1 | NULL | 1 | NULL | 0 | 4 |
| Marcus | 1 | NULL | 1 | NULL | 0 | 4 |
| Paduk | 2 | Unknown | 0 | Baird | 1 | 1 |
| Paduk | 2 | Unknown | 0 | Baird | 1 | 1 |
+------------+---------+------------------+--------------+----------------+---------------+------+
10 rows in set (0.00 sec)
How to repeat:
Run the following script:
-- MySQL dump 10.13 Distrib 8.0.22, for Win64 (x86_64)
--
-- Host: localhost Database: GearsOfWarQueryTest
-- ------------------------------------------------------
-- Server version 8.0.21
/*!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 */;
--
-- Table structure for table `Gears`
--
DROP TABLE IF EXISTS `Gears`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `Gears` (
`Nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`SquadId` int NOT NULL,
`FullName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`CityOfBirthName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`AssignedCityName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
`Rank` int NOT NULL,
`LeaderNickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
`LeaderSquadId` int NOT NULL,
`HasSoulPatch` tinyint(1) NOT NULL,
`Discriminator` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
PRIMARY KEY (`Nickname`,`SquadId`),
UNIQUE KEY `AK_Gears_FullName` (`FullName`),
KEY `IX_Gears_AssignedCityName` (`AssignedCityName`),
KEY `IX_Gears_CityOfBirthName` (`CityOfBirthName`),
KEY `IX_Gears_LeaderNickname_LeaderSquadId` (`LeaderNickname`,`LeaderSquadId`),
KEY `IX_Gears_SquadId` (`SquadId`),
CONSTRAINT `FK_Gears_Cities_AssignedCityName` FOREIGN KEY (`AssignedCityName`) REFERENCES `Cities` (`Name`) ON DELETE RESTRICT,
CONSTRAINT `FK_Gears_Cities_CityOfBirthName` FOREIGN KEY (`CityOfBirthName`) REFERENCES `Cities` (`Name`) ON DELETE CASCADE,
CONSTRAINT `FK_Gears_Gears_LeaderNickname_LeaderSquadId` FOREIGN KEY (`LeaderNickname`, `LeaderSquadId`) REFERENCES `Gears` (`Nickname`, `SquadId`) ON DELETE RESTRICT,
CONSTRAINT `FK_Gears_Squads_SquadId` FOREIGN KEY (`SquadId`) REFERENCES `Squads` (`Id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_as_cs;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `Gears`
--
LOCK TABLES `Gears` WRITE;
/*!40000 ALTER TABLE `Gears` DISABLE KEYS */;
INSERT INTO `Gears` (`Nickname`, `SquadId`, `FullName`, `CityOfBirthName`, `AssignedCityName`, `Rank`, `LeaderNickname`, `LeaderSquadId`, `HasSoulPatch`, `Discriminator`) VALUES ('Baird',1,'Damon Baird','Unknown','Jacinto',2,'Marcus',1,1,'Officer'),('Cole Train',1,'Augustus Cole','Hanover','Jacinto',1,'Marcus',1,0,'Gear'),('Dom',1,'Dominic Santiago','Ephyra','Ephyra',2,'Marcus',1,0,'Gear'),('Marcus',1,'Marcus Fenix','Jacinto',NULL,4,NULL,0,1,'Officer'),('Paduk',2,'Garron Paduk','Unknown','Unknown',1,'Baird',1,0,'Gear');
/*!40000 ALTER TABLE `Gears` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `LocustLeaders`
--
DROP TABLE IF EXISTS `LocustLeaders`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `LocustLeaders` (
`Name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`ThreatLevel` smallint NOT NULL,
`ThreatLevelByte` tinyint unsigned NOT NULL,
`ThreatLevelNullableByte` tinyint unsigned DEFAULT NULL,
`Discriminator` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`LocustHordeId` int DEFAULT NULL,
`DefeatedByNickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
`DefeatedBySquadId` int DEFAULT NULL,
`HighCommandId` int DEFAULT NULL,
PRIMARY KEY (`Name`),
UNIQUE KEY `IX_LocustLeaders_DefeatedByNickname_DefeatedBySquadId` (`DefeatedByNickname`,`DefeatedBySquadId`),
KEY `IX_LocustLeaders_HighCommandId` (`HighCommandId`),
KEY `IX_LocustLeaders_LocustHordeId` (`LocustHordeId`),
CONSTRAINT `FK_LocustLeaders_Factions_LocustHordeId` FOREIGN KEY (`LocustHordeId`) REFERENCES `Factions` (`Id`) ON DELETE RESTRICT,
CONSTRAINT `FK_LocustLeaders_Gears_DefeatedByNickname_DefeatedBySquadId` FOREIGN KEY (`DefeatedByNickname`, `DefeatedBySquadId`) REFERENCES `Gears` (`Nickname`, `SquadId`) ON DELETE RESTRICT,
CONSTRAINT `FK_LocustLeaders_LocustHighCommands_HighCommandId` FOREIGN KEY (`HighCommandId`) REFERENCES `LocustHighCommands` (`Id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_as_cs;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `LocustLeaders`
--
LOCK TABLES `LocustLeaders` WRITE;
/*!40000 ALTER TABLE `LocustLeaders` DISABLE KEYS */;
INSERT INTO `LocustLeaders` (`Name`, `ThreatLevel`, `ThreatLevelByte`, `ThreatLevelNullableByte`, `Discriminator`, `LocustHordeId`, `DefeatedByNickname`, `DefeatedBySquadId`, `HighCommandId`) VALUES ('General Karn',3,3,3,'LocustLeader',1,NULL,NULL,NULL),('General RAAM',4,4,4,'LocustLeader',1,NULL,NULL,NULL),('High Priest Skorge',1,1,1,'LocustLeader',1,NULL,NULL,NULL),('Queen Myrrah',5,5,5,'LocustCommander',1,'Marcus',1,1),('The Speaker',3,3,3,'LocustLeader',2,NULL,NULL,NULL),('Unknown',0,0,NULL,'LocustCommander',2,NULL,NULL,1);
/*!40000 ALTER TABLE `LocustLeaders` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Dumping events for database 'GearsOfWarQueryTest'
--
--
-- Dumping routines for database 'GearsOfWarQueryTest'
--
/*!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 */;
Suggested fix:
Make sure semantically equal queries, like the ones posted, return the same results.