Hi!
Die Eindeutigkeit liegt einzig und allein in dem PK. Aber nach diesem wird ja nicht gesucht, statt dessen wird zb eben nach der Position sortiert.
Problem erkannt. Selbiges ist, dass vom DBMS zuerst die WHERE-Klausel ausgewertet wird und dann erst die Ergebnismenge sortiert wird. Um alle kleineren (oder größeren) Datensätze per WHERE-Bedingung einschließen zu können, muss das Sortierkriterium als Bedingung herhalten. Bei einem Unique-Kriterium ist das kein Problem. Aber, wie wäre es für Vorgänger damit:
WHERE IF(position < $currentPosition, TRUE, IF(position > $currentPosition, FALSE, id < $currentID))
Mit kleineren Positionen sind es sowieso Vorgänger, ansonsten mit größeren sind es Nachfolger und für die Vorgänger-Abfrage nicht interessant. Übrig bleiben die gleichen und da entscheidet die ID. Alles was kleiner ist, ist Vorgänger. Nun noch absteigend sortieren und limitieren.
Für Nachfolger gilt das gleiche Prinzip, nur angepasst.
Einfacher als die verschachtelten IFs ginge es, wenn man beide Sortierkriterien zu einem kombinieren könnte (CONCAT()). Aber das geht bei Zahlenwerten als Kriterien nur, wenn man sie auf gleiche Länge bringt (führende Nullen) (oder sich was anderes eindeutig verknüpfendes als CONCAT() findet).
Lo!