I have a table like this:
CREATE TABLE rows(
UniqueID VARCHAR(225),
Previous VARCHAR(225),
Next VARCHAR(225)
);
With content, that looks like this:
+----------+-----------+-----------+
| UniqueID | Previous | Next |
+----------+-----------+-----------+
| 676 | undefined | 219 |
| 890 | 219 | undefined |
| 219 | 676 | 890 |
+----------+-----------+-----------+
As you can see, the rows have UID's, which the Previous
and Next
columns refer to.
What I now want, is to write a SELECT * statement, that would order all the results, by the Previous
and Next
fields. The undefined
values mark the end elements. How could I achieve that? In the case of the table showed above, the order I'd want is what's shown there, with the last 2 row positions swapped, so Next
of row X Points to a UID of row Y, that has a Previous
that points to the UID of the row X. etc.
What you're trying to create is a recursive query. Unfortunately, MySQL does not make this easy. There are relatively simple solutions if the parents always have an index greater than the children, but that is not the case here. There are several questions discussing this type of problem. The following question has answers that explore the different ways to attempt this type of query including using stored procedures.
How to do the Recursive SELECT query in MySQL?
Going with the stored procedure idea, you could try something like:
CREATE PROCEDURE getInOrder()
BEGIN
DECLARE child_id VARCHAR(256);
DECLARE prev_id VARCHAR(256);
SELECT UniqueID INTO prev_id FROM rows WHERE Previous = 'undefined';
SELECT `Next` INTO child_id
FROM rows WHERE UniqueID = prev_id;
CREATE TEMPORARY TABLE IF NOT EXISTS temp_table AS (SELECT * FROM rows WHERE 1=0);
TRUNCATE TABLE temp_table;
WHILE child_id <> 'undefined' DO
INSERT INTO temp_table SELECT * FROM rows WHERE UniqueID = prev_id;
SET prev_id = child_id;
SELECT `Next` INTO child_id
FROM rows WHERE UniqueID = prev_id;
END WHILE;
INSERT INTO temp_table SELECT * FROM rows WHERE UniqueID = prev_id;
SELECT * FROM temp_table;
END;
You can then call the stored procedure to retrieve the table in order.
Working example: http://sqlfiddle.com/#!9/085dec/2
ORDER BY IFNULL(prev, ''), -- some value lower than the rest
IFNULL(next, 'zzzzz') -- some value higher than all values
(Technically, the first part could be simply prev
, without the IFNULL
.)
If the ids are really numbers, you should use a numeric datatype such as INT UNSIGNED
. If they are really strings, do you need 225?
This assumes that prev < next -- Is that necessarily the case? It seems like arbitrary links might not maintain that. If you need to look at next
to load the next row based on UniqueId
, the code is much more complex.
I think this request lacks on details.
But, you want the final result to be like this?
+----------+-----------+-----------+
| UniqueID | Previous | Next |
+----------+-----------+-----------+
| 676 | undefined | 219 |
| 219 | 676 | 890 |
| 890 | 219 | undefined |
+----------+-----------+-----------+
If I'm right, you can achieve it with (I named the table as demo
):
SELECT d.* FROM (
SELECT UniqueID, IF(Previous IS NULL, -1, Previous) AS Previous, IF(Next IS NULL, 999999999999, Next) as Next
FROM demo
)t
JOIN demo d ON d.UniqueID = t.UniqueID
ORDER BY t.Next, t.Previous
;
So, when Previous
is NULL
you put it with -1 to ensure he's is the first on the list and when Next
is NULL
you put it with a very high value to ensure it will be the last on the list... then you just have to order the query by Previous
and Next
.
I must stress that this solution is focused on presented data.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.