Hello stack overflow community. I've got a following problem.
Given the following, I have an entries table
CREATE TABLE `entries` (
`name` varchar(50) DEFAULT NULL,
`sort_order` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Which contains the following values:
INSERT INTO `entries` (`name`, `sort_order`) VALUES
('a', NULL),
('c', 2),
('b', 3),
('d', NULL),
('e', NULL),
('f', NULL),
('g', NULL),
('h', NULL),
('i', 5),
('ii', 4);
What is the best possible way to query and sort values by name asc keeping values with defined sort_order in its positions?
I tried different workarounds with ROW_NUMBER() and CTE but nothing worked.
Here's the query, however it returns incorrect results.
WITH ranked_entries AS (
SELECT
*,
ROW_NUMBER() OVER (ORDER BY `name` ASC) AS `rn`
FROM entries
),
merged_entries AS (
SELECT
*,
COALESCE (`sort_order`, `rn`) AS merged_rank
FROM ranked_entries
)
SELECT * FROM merged_entries ORDER BY merged_rank ASC;
The expected result should be the following:
name | sort_order |
---|---|
a | 1 |
c | 2 |
b | 3 |
ii | 4 |
I | 5 |
d | 6 |
e | 7 |
f | 8 |
g | 9 |
h | 10 |
Why not possible ?
So, the logic behind this answer is,
sort_order is not null
- Table T1
sort_order is null
- Table T2
Now create an empty table, T0
with length of entries
with columns name
as empty data and rn
as ROW_NUMBER() OVER (ORDER BY NULL)
.
And tables are showing as follows:
Now, join Tables T0
& T1
on columns rn, short_order respectively, to get the Table T3
and also create a row_number
(name_null_rn
) where name is null
Then, join Tables T3
& T2
on columns name_null_rn
& rn
respectively and merge T3
& T2
names in that joining.
Your Final Query is:
with T0 AS (
select '' as name,
ROW_NUMBER() OVER (ORDER BY NULL) AS `rn`
from entries
),
T1 as (
select *
from entries
where sort_order is not null
order by sort_order asc
) -- select * from T1
, T2 as (
select name,
ROW_NUMBER() OVER (ORDER BY `name` ASC) AS `rn`
from entries
where sort_order is null
order by name asc
) -- select * from T2;
, T3 as (
SELECT
T1.name as name,
T0.rn,
case when (T1.name is null)
then row_number() over (partition by T1.name)
end as name_null_rn
from T0 LEFT JOIN T1
ON T0.rn = T1.sort_order
) -- select * from T3;
select
COALESCE(T3.name, T2.name) as name,
T3.rn as sort_order
from T3 left join T2
on T3.name_null_rn = T2.rn
order by T3.rn;
Final Output already show in attached image.
Check Sample query line by line: db<>fiddle
Happy Coding !!!!!!
@user3486769
After understanding my logic you can modify SQL query. I could make it complicated. Since this is a complex question, I made it as simple as possible.
Modify the query according to your requirements.