add batch remove batch split batch comment selection show hidden batches hide batch highlight batch
db<>fiddle
donate feedback about
By using db<>fiddle, you agree to license everything you submit by Creative Commons CC0.
CREATE TABLE toys (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50) NOT NULL,
rank_index TINYINT UNSIGNED,
created_at DATETIME NOT NULL
);
INSERT INTO toys VALUES
(NULL, 'An awesome product', NULL, '2023-01-01 10:04:00'),
(NULL, 'Another product', 4, '2023-01-01 10:00:00'),
(NULL, 'Baby car', NULL, '2023-01-01 10:05:00'),
(NULL, 'Green carpet', 2, '2023-01-01 10:08:00'),
(NULL, 'Toy', NULL, '2023-01-01 10:07:00');
Records: 5  Duplicates: 0  Warnings: 0
SELECT * FROM toys;
id title rank_index created_at
1 An awesome product null 2023-01-01 10:04:00
2 Another product 4 2023-01-01 10:00:00
3 Baby car null 2023-01-01 10:05:00
4 Green carpet 2 2023-01-01 10:08:00
5 Toy null 2023-01-01 10:07:00
WITH RECURSIVE seq (n) AS (
SELECT 1 UNION ALL SELECT n + 1 FROM seq WHERE n < (SELECT COUNT(*) FROM toys)
)
SELECT title, rank_index, created_at, n
FROM (
SELECT seq.n, ROW_NUMBER() OVER (ORDER BY seq.n) AS rn
FROM seq
WHERE NOT EXISTS (SELECT 1 FROM toys WHERE rank_index = seq.n)
) x
JOIN (
SELECT *, ROW_NUMBER() OVER (ORDER BY created_at DESC) rn
FROM toys
WHERE rank_index IS NULL
) y USING (rn)

UNION ALL

SELECT title, rank_index, created_at, rank_index
FROM toys
WHERE rank_index IS NOT NULL

-- applies to the result of the UNION
ORDER BY n;
title rank_index created_at n
Toy null 2023-01-01 10:07:00 1
Green carpet 2 2023-01-01 10:08:00 2
Baby car null 2023-01-01 10:05:00 3
Another product 4 2023-01-01 10:00:00 4
An awesome product null 2023-01-01 10:04:00 5
-- this cte just gives is a contiguous sequence from 1 to number of toys
WITH seq (n) AS (
SELECT ROW_NUMBER() OVER (ORDER BY id) FROM toys
)
SELECT title, rank_index, created_at, n
FROM (
-- we now add row_number to the seq after removing the seq numbers
-- already used by rank_index
SELECT seq.n, ROW_NUMBER() OVER (ORDER BY seq.n) AS rn
FROM seq
WHERE NOT EXISTS (SELECT 1 FROM toys WHERE rank_index = seq.n)
) x
JOIN (
-- get toys without rank_index and add row_number for join to prev subquery
SELECT *, ROW_NUMBER() OVER (ORDER BY created_at DESC) rn
FROM toys
WHERE rank_index IS NULL
) y USING (rn)

UNION ALL

SELECT title, rank_index, created_at, rank_index
FROM toys
WHERE rank_index IS NOT NULL

-- applies to the result of UNION
ORDER BY n;
title rank_index created_at n
Toy null 2023-01-01 10:07:00 1
Green carpet 2 2023-01-01 10:08:00 2
Baby car null 2023-01-01 10:05:00 3
Another product 4 2023-01-01 10:00:00 4
An awesome product null 2023-01-01 10:04:00 5