Here are two alternatives:
The first consists of using a junction (with the table itself). This is a portable solution, since it only uses standard SQL language elements or functionality, and which are available in (almost) all database management systems.
SELECT P1.*
FROM produtos P1
LEFT JOIN
(
SELECT RELATED, MAX(ID) MAX_ID
FROM produtos
WHERE RELATED IS NOT NULL
GROUP BY RELATED
) AS P2
ON P2.related = P1.RELATED
ORDER BY CASE WHEN P2.RELATED IS NULL THEN P1.ID ELSE P2.MAX_ID END DESC, P1.ID DESC
The idea is to identify the products for which information exists in the RELATED column, and for each of the RELATED codes to identify the corresponding maximum ID. This information will be used as the sort criterion as follows:
ORDER BY CASE WHEN P2.RELATED IS NULL THEN P1.ID ELSE P2.MAX_ID END DESC
The result will be the one you indicated in your question:
| ID | TITLE | RELATED |
| --- | -------- | ------- |
| 5 | casaco | |
| 4 | moletom | 123456 |
| 2 | camiseta | 123456 |
| 3 | calca | |
| 1 | tenis | |
The second alternative makes use of the window functions available in the latest versions of Mysql.
SELECT ID,
TITLE,
RELATED,
MAX(ID) OVER (PARTITION BY CASE WHEN RELATED IS NOT NULL THEN RELATED ELSE ID END) AS SortingOrder
FROM produtos
ORDER BY 4 DESC, ID DESC
;
The result will be the same as the previous version.
| ID | TITLE | RELATED | SortingOrder |
| --- | -------- | ------- | ------------ |
| 5 | casaco | | 5 |
| 4 | moletom | 123456 | 4 |
| 2 | camiseta | 123456 | 4 |
| 3 | calca | | 3 |
| 1 | tenis | | 1 |
I don’t think you can do that with a query "". There must be some intermediate logic there.
– João Martins