Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Zmiana liczb porządkowych rekordów
Forum PHP.pl > Forum > Bazy danych > MySQL
Pilsener
Załóżmy mam tabelę:

ID||Lp||Nazwa
1||2||abc
2||4||xyz
3||1||qwerty
4||3||asd

Pole lp jest dodane po to, aby użytkownik mógł decydować o kolejności wyświetlania elementów (taki bajer, poza standardowym sortowaniem np. po nazwie)

Otóż w formularzu użytkownik sobie wybiera (lub wpisuje), że np. pozycja o ID 3 ma mieć pozycję 4-tą, więc trzeba jej zmienić LP na 4 a pozostałe rekordy odpowiednio zmodyfikować, by wyglądało tak:

ID||Lp||Nazwa
1||1||abc
2||3||xyz
3||4||qwerty
4||2||asd

Zrobiłem pętlę, która za jednym obrotem updatuje jeden rekord, jednak nie jest to zbyt wydajne rozwiązanie i zastanawiam się, czy nie można tego rozwiązać jednym-dwoma zapytaniami? Lub może mam złe podejście do problemu?

Stąd prośba do Was.
Foxx
Ale po co Ci pętla, przetwarzasz wszystkie rekordy? Przecież musisz tylko zamienić dwa numery ze sobą (ten który poda user z tym, który aktualnie jest pod tym lp).
Pilsener
No jak, przecież zmieniają się wszystkie:
1 - z 2 na 1
2 - z 4 na 3
3- z 1 na 4
4 - z 3 na 2

Część lp spadnie o jedną pozycję (-1) a część wzrośnie (+1) - gdybym zrobił tak jak mówisz to albo miałbym dwa identyczne lp, albo zamieniłbym miejscami pozycje 1 z 4-tą, a po spadku ID 3 z pozycji 1 na 4-tą na pierwsze miejsce ma wskoczyć dotychczasowa druga pozycja, a nie czwarta - czwarta ma być teraz trzecia.

Nie wiem jak to lepiej wytłumaczyć...
Foxx
Czyli to nie do końca jest sortowanie bo kolejność elementów zawsze będzie taka sama w tym systemie.
Nazwałbym to raczej określaniem, który element jest pierwszy. Więc może zamiast tego co robisz dodaj tylko jakiś znacznik mówiący o tym, który z rekordów ma być w tym momencie pierwszy?
Pilsener
Niestety to nic nie pomoże, musi być możliwość dowolnego poukładania rekordów poprzez przesuwanie pojedyńczej pozycji w górę lub w dół o n miejsc lub odgórne wskazanie miejsca w hierarchi. Po to właśnie zostało dodane do bazy to pole - pozostaje tylko elegancko ogarnąć zapytanie do tego.

Identyczny problem powstaje przy usuwaniu rekordu - "dziura" musi zostać ładnie wypełniona, ale tu widzę mniejszy problem, bo wszystkie lp dla rekordów poniżej skasowanego wystarczy updatować +1. Przy dodawaniu jest jeszcze łatwiej, bo nowy rekord automatycznie trafia na koniec, czyli max(lp)+1.
artur_dziocha
jesli dobrze rozumiem to są przeciez 2 operacje
1. znajdujesz element o lp niższym o 'n' i tam zwiekszasz o 'n'
2. zmniejsz o 'n' w zmienianych
I chyba to wszystko:)
z usuwaniem też możesz sobie latwo poradzić żeby nie bylo dziur. Po usunieciu wiersza pobierasz wszystko tworzysz tablice z 'id' i 'lp' jako ireacyjne $i
i później update bazy.

~ Literówki
Pilsener
Ok, czyli załóżmy, że mam 10 rekordów i chcę przesunąć rekord z 7-mej pozycji na 4-tą:

1. Rekordy 1-3 oraz 8-10 nie zmieniają się
2. Rekordy na pozycjach 4-6 dostają +1
3. Rekord 7 dostaje lp=4

Analogicznie przy przesuwaniu w dół np. z 3-ciej na 8-mą:
1. Rekordy 1-2 i 9-10 nie zmienią się
2. Rekordy na pozycjach 4-8 dostają -1
3. Rekord 3 dostaje lp=8

Chyba nie da się tego zrobić prościej, ale lepsze dwa zapytania niż po jednym dla każdego rekordu. Poeksperymentuję dziś wieczorem z tym winksmiley.jpg
kefirek
Można tez spróbować tak powinno chyba dzialac
  1. UPDATE id SET lp = CASE lp
  2. WHEN id=2 THEN 7
  3. WHEN lp > 7 THEN lp+1
  4. ELSE lp-1 END


Gdzie 2 to id jakie zmieniasz
Warunek sprawdza czy ID jest równe temu ID co chcesz zmienić jak tak zmieniasz na podaną wartość potem warunek sprawdzasz czy LP jest większe od podanej wartości ( w tym przykładzie 7 )jak tak to dodaje 1 a na końcu sprawdzasz czy mniejsze jak tak odejmuje 1
mongea
hi

slp - stare lp
nlp - nowe lp
czyli np. z 4-tej pozycji (slp) na 7-ma (nlp)

jednym zapytaniem niezaleznie od kierunku/braku zmiany:

UPDATE tab
SET lp = IF (lp = slp, nlp, lp + SIGN(slp - nlp))
WHERE lp >= LEAST(nlp, slp) AND lp <= GREATEST(nlp, slp)
Pilsener
Wielkie dzięki, śmiga jak burza.

Mam jeszcze jedno pytanko, czy na podobnej zasadzie mogę sprowadzić numery rekordów:

id||lp
x||8
x||5
x||2
x||9

Do postaci:
id||lp
x||3
x||2
x||1
x||4

Także jednym zapytaniem? Kombinuję z tymi IF+CASE, ale moje doświadczenie w tym zakresie jest znikome, prosiłbym chociaż o wskazówkę.

Edit: dzięki ponownie, nie wiedziałem, że nawet można używać zmiennych w zapytaniach - toż to cały język smile.gif Bardzo mi to pomoże powiększyć funkcjonalność przy zachowaniu zdroworozsądkowej liczby zapytań do bazy.
mongea
ponumerowanie z pozbyciem sie luk i zachowaniem porzadku:

UPDATE tab SET lp = (SELECT @nlp:=@nlp+1 nlp FROM (SELECT @nlp:=0) flp) ORDER BY lp

@nlp - dowolna nazwa zmiennej
rozna nazwa aliasow (nlp i flp)

dzialaj smile.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.