Bug #113154 Join using ROW_NUMBER() returns incorrect records
Submitted: 20 Nov 2023 21:57 Modified: 21 Nov 2023 6:10
Reporter: Roman Odaisky Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: DML Severity:S2 (Serious)
Version:8.2.0, 8.1.0, 8.0.35 OS:Linux
Assigned to: CPU Architecture:Any

[20 Nov 2023 21:57] Roman Odaisky
Description:
The following SQL tries to join two tables, using ROW_NUMBER() to select only one child record for each parent record. MySQL incorrectly returns multiple records. The example seems to be minimal, delete anything and the bug disappears.

How to repeat:
DROP TABLE IF EXISTS `parent`;
CREATE TABLE `parent` (
  `id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY
) ENGINE=InnoDB;

DROP TABLE IF EXISTS `child`;
CREATE TABLE `child` (
  `id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `parent_id` bigint NOT NULL,
  `seq` int DEFAULT NULL
) ENGINE=InnoDB;

INSERT INTO `parent` VALUES (40);

INSERT INTO `child` VALUES
( 1, 10, 100),
( 2, 20, 200),
( 3, 30, 200),
( 4, 40, 200), -- highest seq for this parent_id
( 5, 50, 200),
( 6, 40, 100), -- lowest seq for this parent_id
( 7, 60, 200),
( 8, 70, 200),
( 9, 80, 100),
(10, 10, 100);

-- For each parent, which child has the highest `seq`?
SELECT t.id_top
FROM (
    SELECT
        c.id AS id_top,
        ROW_NUMBER() OVER (PARTITION BY c.parent_id ORDER BY c.seq DESC) AS rn
    FROM child c
) t
WHERE t.rn = 1;
-- Output: all but 6 and 10, as expected

-- Let’s now join each parent (well, we only have one) with its top child by `seq`.
SELECT child_top.id
FROM parent
LEFT OUTER JOIN child child_top ON (
    parent.id = child_top.parent_id
    AND child_top.id IN (
        SELECT t.id_top
        FROM (
            SELECT
                c.id AS id_top,
                ROW_NUMBER() OVER (PARTITION BY c.parent_id ORDER BY c.seq DESC) AS rn
            FROM child c
        ) t
        WHERE t.rn = 1
    )
);
-- Output: 4, 6
-- Expected: only 4
[21 Nov 2023 6:10] MySQL Verification Team
Hello Roman Odaisky,

Thank you for the report and test case.

regards,
Umesh