Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php][mysql] zmiana liczby porządkowej rekordu
Forum PHP.pl > Forum > Przedszkole
mpps
witam,
mam taki problem:
chcę zmieniać liczbę porządkową rekordu za pomocą skryptu php w trakcie uaktualniania danych w bazie.

wyglądać ma to tak:

1. stan początkowy:

position | rekord
-------------------
1 | rekord1
2 | rekord2
3 | rekord3
4 | rekord4
5 | rekord5

2. po zmianie:

position | rekord
-------------------
1 | rekord1
2 | rekord5
3 | rekord2
4 | rekord3
5 | rekord4

3. po kolejnej zmianie:

position | rekord
-------------------
1 | rekord1
2 | rekord2
3 | rekord5
4 | rekord3
5 | rekord4

  1. IF($position!=$rek[position]){
  2. mysql_query("UPDATE tabela SET position=position+1 WHERE position>=$position") OR die(mysql_error());
  3. }


powyższe rozwiązanie powoduje, że po każdym uaktualnieniu danych, czyli zmianie którejś z pozycji, te, które mają wyższą liczbę porządkową zwiększają ją o 1.
problem tkwi w tym, że jeśli po raz kolejny uaktualnię dane w tabeli, te z wyższą liczbą porządkową znowu zwiększają ją o 1.

wygląda to wtedy tak:

1. stan początkowy:

position | rekord
-------------------
1 | rekord1
2 | rekord2
3 | rekord3
4 | rekord4
5 | rekord5

2. po zmianie:

position | rekord
-------------------
1 | rekord1
2 | rekord5
3 | rekord2
4 | rekord3
5 | rekord4

3. po kolejnej zmianie:

position | rekord
-------------------
1 | rekord1
2 | rekord2
3 | rekord5
5 | rekord3
6 | rekord4

jak zastosować pętlę, żeby rekord3 miał lp 4 a rekord4 lp 5?

pozdrawiam
Wieviór
Generalnie chcesz osiągnąć to, że podnosić powiedzmy rekord 5 o jeden do góry, i te co są nad nim, mają opadać pod niego, tak? Czyli po prostu masz powiedzmy menu, każdy link oddzielny rekord, i ustalasz ich pozycję, poprzez strzałki góra/dół w administracji, tak?
mpps
nie,
chodzi o to, żeby po każdej zmianie pozycji rekordu w bazie liczby porządkowe były zawsze po kolei, czyli:
1.
2.
3.
4.
5.

a nie:
1.
2.
3.
6.
28.

za każdym uaktualnieniem bazy (UPDATE) liczba porządkowa rekordów z większym position byłaby zmieniana - niektóre w dół, niektóre w górę, niektóre nie zmieniałyby swojej pozycji.
jeśli dasz 5 po 1, to: 2->3, 3->4 a 4->5
kolejna zmiana - dajemy 2 po 1 i mamy: 5->3, 3->5, 4->6 (znika nam lp 4).
w ten sposób robią się coraz większe 'dziury' między cyferkami winksmiley.jpg
tego chcę uniknąć
nowotny
Ja wymyśliłem coś takiego:
  1. <?php
  2. $position_doc='7';//pozycja docelowa gdzie chcemy umiescic rekord
  3. $rekord='trzy';//nazwa rekordu ktory chcemy przesunac
  4.  
  5. $query='SELECT * FROM tabela WHERE rekord="'.$rekord.'"';
  6. $result=mysql_query($query);
  7. $res=mysql_fetch_assoc($result);
  8. $rekord_current_position=$res['position'];
  9.  
  10. if($rekord_current_position>$position_doc) {
  11. $direction='back';
  12. $query='SELECT * FROM `tabela` WHERE `position` BETWEEN '.$position_doc.' AND '.$rekord_current_position.';';
  13. }
  14. else {
  15. $direction='forw';
  16. $query='SELECT * FROM `tabela` WHERE `position` BETWEEN '.$rekord_current_position.' AND '.$position_doc.';';
  17. }
  18.  
  19. $result=mysql_query($query);
  20. while ($row = mysql_fetch_assoc($result)) {
  21. if($row['position']==$rekord_current_position){
  22. $query='UPDATE tabela SET position="'.$position_doc.'" WHERE rekord="'.$row['rekord'].'"';
  23. }
  24. else{
  25. if($direction=='forw'){
  26. $query='UPDATE tabela SET position="'.($row['position']-1).'" WHERE rekord="'.$row['rekord'].'"';
  27. }
  28. else{
  29. $query='UPDATE tabela SET position="'.($row['position']+1).'" WHERE rekord="'.$row['rekord'].'"';
  30. }
  31. }
  32. mysql_query($query);
  33. }
  34. ?>


I mam nadzieje że nie masz pola "position" zdefiniowanego jako AUTOINCREMENT... winksmiley.jpg
Wieviór
Cytat(nowotny @ 7.02.2008, 00:40:21 ) *


Ogólnie wygląda to dobrze chyba, tylko trzeba pamiętać, że w pierwszym if'ie else oznacza =<, a więc też gdy są sobie równe, i choć nic to nie zmieni, to warto dodać elseif < i elseif =, bo nie trzeba wtedy robić zapytania do bazy.

Inna sprawa, że proponuję lekką optymalizacje:

  1. <?php
  2. $position_doc='7';//pozycja docelowa gdzie chcemy umiescic rekord
  3. $rekord='trzy';//nazwa rekordu ktory chcemy przesunac
  4.  
  5. $query='SELECT position FROM tabela WHERE rekord="'.$rekord.'"';
  6. $result=mysql_query($query);
  7. $rekord_current_position=mysql_fetch_assoc($result);
  8.  
  9. if($rekord_current_position>$position_doc) {
  10. $direction='back';
  11. $query='SELECT position FROM `tabela` WHERE `position` BETWEEN '.$position_doc.' AND '.$rekord_current_position.';';
  12. }
  13. else {
  14. $direction='forw';
  15. $query='SELECT position FROM `tabela` WHERE `position` BETWEEN '.$rekord_current_position.' AND '.$position_doc.';';
  16. }
  17.  
  18. $result=mysql_query($query);
  19. while ($row = mysql_fetch_assoc($result)) {
  20. if($row==$rekord_current_position){
  21. $query='UPDATE tabela SET position="'.$position_doc.'" WHERE rekord="'.$row['rekord'].'"';
  22. }
  23. else{
  24. if($direction=='forw'){
  25. $query='UPDATE tabela SET position="'.($row['position']-1).'" WHERE rekord="'.$row['rekord'].'"';
  26. }
  27. else{
  28. $query='UPDATE tabela SET position="'.($row['position']+1).'" WHERE rekord="'.$row['rekord'].'"';
  29. }
  30. }
  31. mysql_query($query);
  32. }
  33. ?>


Nie potrzebne używać * i tworzyć tablicę, wyczytując całą tabelę z bazy danych, jeśli używamy tylko position ;]
mpps
Cytat(nowotny @ 6.02.2008, 22:40:21 ) *
I mam nadzieje że nie masz pola "position" zdefiniowanego jako AUTOINCREMENT... winksmiley.jpg

no, jak bym używał do 'position', to nie potrzebowałbym takiego rozwiązania - za które bardzo Ci dziękuję, bo po lekkich modyfikacjach działa doskonale! Modyfikacje nie wpływają na funkcjonalność, dlatego nie będę zaśmiecał nimi tutaj miejsca. jeszcze raz wielkie dzięki!!
jeśli komuś (może mi?) będzie się chciało, to może na podstawie Twojego rozwiązania rozwinąć temat i stworzyć np. skrypt do numerowania 'na nowo' danych w bazie.
spotkałem się na tym forum wielokrotnie z pytaniem o możliwość optymalizacji bazy pod kątem nadania nowego 'id' w sytuacji, kiedy używa się 'auto_increment' i wiadomo, że po wyrzuceniu jakiegoś rekordu powstają 'dziury'.
wiem, wiem, że zmiana 'id' może powodować błędy, itd, bla, bla, ale są takie sytuacje, kiedy taka zmiana jest pożądana!

Cytat(Wieviór @ 7.02.2008, 13:33:28 ) *
Inna sprawa, że proponuję lekką optymalizacje:
Nie potrzebne używać * i tworzyć tablicę, wyczytując całą tabelę z bazy danych, jeśli używamy tylko position ;]

a nie prawda!
jak zassiesz z bazy tylko 'position', to jest problem, ponieważ nie zostanie zmieniona pozycja elementu, który już taką pozycję ma (pole nie jest 'primary', bo być nie może)!
czyli, jeśli zmienisz 9->6, to 6->6 a nie 6->7
jeszcze nie wiem czemu ale właśnie to sprawdzam

od siebie dodaję zmianę w sytuacji usuwania rekordu:
  1. $result = mysql_query("SELECT * FROM tabela WHERE id=$id") OR die(mysql_error());
  2. $rek = mysql_fetch_array($result);
  3. mysql_query("DELETE FROM tabela WHERE id=$id") OR die(mysql_error());
  4.  
  5. // zmiana position dla wpisow z wyzszymi pozycjami
  6. $rekord=$id; //id rekordu, ktory usuwamy
  7. $rekord_current_position=$rek[position]; //position rekordu, ktory usuwamy
  8.  
  9. $query="SELECT * FROM tabela WHERE position>$rekord_current_position";
  10.  
  11. $result=mysql_query($query);
  12. while($row = mysql_fetch_assoc($result)){
  13. $query="UPDATE tabela SET position=($row[position]-1) WHERE id=$row[id]";
  14. mysql_query($query);
  15. }

proste ale jeśli ktoś będzie potrzebował, to ma komplet

pozdrawiam i dzięki!
Wieviór
Słusznie, nie zauważyłem, że tam się jeszcze pole rekord pojawia. No to daj wszędzie zamiast "tabela" - "rekord, tabela". No chyba, że to są jedyne pola w tej tabeli, wtedy możesz dać rzeczywiście * ;]
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.