• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

SQL Positionen Ordnen

forwardpoint

New member
Hallo Zusammen,

Ich versuche folgendes:

Code:
function freeposition($ID, $pos, $tab)
   {
   global $laspri;
   if($ID == "NULL")
      {
      $primaryquery=
      'SELECT `PRIMARY` from '.$tab.' WHERE `position` = '.$pos;
         $result = mysql_query($primaryquery) or die("Anfrage fehlgeschlagen: " . mysql_error());
         $line = mysql_fetch_row($result);
      
      if(!isset($line[0]))
         {
         return "done";
         }
      else
         {
         $newpos = $pos + 1;
         freeposition($line[0], $newpos, $tab);
         return 'done';
         }
      }
   else
   {
   if(isset($ID)&&isset($pos)&&isset($tab))
      {
         $primaryquery=
         'SELECT `position` from '.$tab.' WHERE `PRIMARY` = '.$ID;
         $result = mysql_query($primaryquery) or die("Anfrage fehlgeschlagen: " . mysql_error());
         $line = mysql_fetch_row($result);
         global $oldpos;
         $oldpos = $line[0];
         if($oldpos == $pos)
            {
            return 'done';
            }
         
         if(isset($oldpos) && $oldpos < $pos)
               {
               $pos = $pos + 1;
               #Print 'Old: '.$oldpos.' New: '.$pos;
               $query = 'UPDATE '.$tab.' 
               SET `POSITION` = 99999
               WHERE `PRIMARY` = '.$ID;
               #Print '<br>Sicherung : '.$query.'<br>';
               $result = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());
               }

      function sub_position($ID, $pos, $tab)
         {
         global $oldpos;
         $primaryquery=
         'SELECT `PRIMARY` from '.$tab.' WHERE `position` = '.$pos;
         $result = mysql_query($primaryquery) or die("Anfrage fehlgeschlagen: " . mysql_error());
         $line = mysql_fetch_row($result);
         $newpri = $line[0];
         #Print 'newpri '.$newpri.'<br>';
         if(!$newpri)
            {
            $query = 'UPDATE '.$tab.' 
            SET `POSITION` = '.$pos.'
            WHERE `PRIMARY` = '.$ID;
            #Print '<br>newPrimary: '.$query.'<br>';
            $result = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());
            return $pos;
            }

         else
            {
            $lastpri = $line[0];
            $pos = $pos + 1;
            $ret = sub_position($lastpri, $pos, $tab);
            #Print '<br>Return: '.$ret;
            return $ret;
            }
         }


      $test = sub_position($ID, $pos, $tab);

      #Print '<br>PRIMARY: '.$ID.' Test: '.$test.' Pos: '.$pos.' <br>';

      while($test > $pos)
         {
         $test = sub_position($ID, $pos, $tab);
         }
      $query = 'UPDATE '.$tab.' 
      SET `POSITION` = '.$pos.'
      WHERE `PRIMARY` = '.$ID;
      #Print '<br>newPrimary: '.$query.'<br>';
      $result = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());
      }

   else
      {
      Print "Nicht genug Variablen für die Funktion sub_position($ID, $pos, $tab) übergeben!<br>";
      Print 'ID = '.$ID.' Position = '.$pos.' Tabelle = '.$tab;
      exit;
      }
   }
   orderposition($tab);
   return 'done';
   }

function orderposition($tabelle)
   {
   $link = db_connect();
   $primaryquery=
   'SELECT `PRIMARY` from '.$tabelle.' ORDER BY `position` ASC';
   #Print '<br>'.$primaryquery;
   $result = mysql_query($primaryquery) or die("Anfrage fehlgeschlagen: " . mysql_error());
   global $counter;
   $counter = 0;
   while ($line = mysql_fetch_array($result, MYSQL_ASSOC))
   {
   foreach($line as $name=>$value)
      {
      $counter = $counter + 1;
      $query = 'UPDATE `'.$tabelle.'` SET `position` = "'.$counter.'" WHERE `PRIMARY` = '.$value;
      #Print '<br>'.$query;
      $result2 = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());
      }
   }
   }


$link = db_connect(); //Geht sicher...

$PRIMARY = 102;
$artikel_position = 5;

Print 'POSITION: '.$artikel_position.' PRIMARY: '.$PRIMARY.'<br><br>';

$toprint = freeposition($PRIMARY, $artikel_position, 'warengruppen');
Print $toprint;

orderposition('artikel')

Geht auch. Aber nur bis 500 Datensätzen.
Oder nur wenn die letzten 500 Betroffen sind.
Andernfalls läuft es in einen Timeout.
Kann ich den Timeout von 90 Sekunden in PHP verlängern oder die Funktionen bzw. das neuordnen und sortieren beschleunigen?

Grüße und Danke für die Hilfe
 
Beschreib mal was du machen willst, habe nämlich keine Lust und Zeit mich durch deinen Code zu arbeiten. Allerdings ist es nicht sehr performant ein Haufen einzelner SQL-Anfragen zu starten. Zumal deine Datenbank im Sortieren sicherlich schneller ist als PHP (wenn du die richtigen Indexe hast)
 
OK Ich versuche es zu beschreiben:
Ich habe eine Tabelle mit PRIMARY als Index und einer Spalte die Position heißt.
Position hat jeder Datensatz in meinem Programm logischerweise nur eine.
Die Spalte Position ist Uniqe.

Code:
PRIMARY - Position
1 - 1
2 - 2
3 - 3
u.s.w.

Wenn jetzt Position 3 nach 1 verschoben werden soll dann muss erst 1 nach 2 verschoben werden. Da 2 schon belegt ist 2 nach 3. 3 ist noch belegt also wird 3 nach 4 verschoben dann 2>3, 1>2, 4>1.

Dann sieht es so aus:
Code:
PRIMARY - Position
1 - 2
2 - 3
3 - 1
u.s.w.

Wie mache ich diesen Vorgang schneller?
Oder einfacher?
Gibt es einen SQL Befehl der Sagt: Rücke alles eins nach oben ab Position 1; Dann mach 3 zu 1; Dann sortiere es?
 
Zuletzt bearbeitet:
Hab' in der MySQL Beschreibung folgendes gefunden (Kap. 11.2.10.):
UPDATE persondata SET age=age+1;
Soweit ich das verstanden habe wird da das Feld 'age' für alle um eines erhöht.

Wenn du nun den ersten Eintrag auf den letzen schiebest (in deinem Bsp: 1->4) und dann für alle ein -1 machst, sollte das das Erwünschte ergeben.
 
Wie mache ich diesen Vorgang schneller?
Oder einfacher?

also auf die schnelle würde mir da einfallen,
SELECT * from tab WHERE position BETWEEN new_pos AND old_pos ORDER BY position DESC;
dann old_pos merken und mit count() + 1 ersetzen
dann in einer schleife über das ergebnis der abfrage nächste pos merken und mit vorheriger ersetzen.
am ende old_pos mit new_pos ersetzen

EDIT: mal als Bsp: new_pos=3; old_pos=5 (bei new_pos=5; old_pos=3 müßte es mit ORDER BY position ASC gehen)
Code:
P  position
   
1  1  
2  2  
3  3  - 4
4  4  - 5
5  5  - 9  - 3
6  6  
7  7  
8  8
 
Zuletzt bearbeitet:
Mit der Schleife hast Du sofort wieder den fucking Timeout. Die Lösung ist richtig. "Richtiger" sogar. Deine Lösung kommt auf bis zu 700 Einträge. Danach kommt wieder der alte Bekannte Fehler 500...
 
und mit kkapsner query?
Code:
UPDATE xxx SET position = 9 WHERE position = 5;
UPDATE xxx SET position = position + 1 WHERE position BETWEEN 3 AND 5 ORDER BY position DESC;
UPDATE xxx SET position = 3 WHERE position = 9;
 
Wenn dein Server das zulässt, kannst du auch mal
PHP:
ini_set("max_execution_time",-1);
am Anfang deines Scriptes ausprobieren.
Damit wird die maximale Zeit auf unendlich gestellt, aber manche Hoster verbieten das in der php.ini.
 
Jo das mit der Knappen Query geht.
Schreibe das grade auf mein Script um.
Aber ich kann jetzt schon mal sagen das der Script um einiges kürzer wird.
Ich stelle ihn rein wenn ich fertig bin.
 
Die SQL-Queries sollten keine 90 Sekunden dauern, auch nicht bei einen paar 1000 Datensätzen. Dein Fehler ist, dass du jeden Datensatz mit einer einzelnen Query bearbeitets. Dazu muss jedesmal die Query von der DB ausgewertet werden, der entsprechende Datensatz gesucht und geändert werden und evtl. anschließend Indexe geupdatet werden. Das produziert eine Unmenge an Overhead.

Du mußt deine Queries also zusammenfassen. Das geht dann nicht nur schneller sondern dein Code wird auch übersichtlicher und dadurch weniger fehleranfällig.

Du hast im wesentlichen 2 Fälle zu berücksichtigen, einmal die neue Position ist größer, einmal die neue Position ist kleiner. Ich gehe mal davon aus das deine pos-Spalte unique ist, (d.h. jeder Wert darf nur einmal auftauchen).
PHP:
function changePos($new, $old)
{
    // Tupel das verschoben werden soll aus pos = -1 parken
    $query = 'UPDATE table SET pos=-1 WHERE pos = '.$old;
    // query ausführen...

    // alle Tupel die zwischen alter und neuer position liegen aufrutschen
    if($old > $new)
    {
        // da alte Position größer ist, muss der Rest nach hinten rutschen, daher +1 und es muss von hinten angefangen werden, da es sonst zu duplicate values kommt, daher DESC
        $query = 'UPDATE table SET pos = pos +1 WHERE pos BETWEEN '.$new.' AND '.$old.' ORDER BY pos DESC';
    }
    else
    {
 // da neue Position größer ist, muss der Rest nach vorne rutschen, daher -1 und es muss von vorne angefangen werden, da es sonst zu duplicate values kommt, daher ASC
        $query = 'UPDATE table SET pos = pos -1 WHERE pos BETWEEN '.$new.' AND '.$old.' ORDER BY pos ASC';
     }
     // $query ausführen

     // jetzt nur noch die geparkte query nach vorne holen
     $query = 'UPDATE table SET pos = '.$new.' WHERE pos=-1';
     // $query ausführen
}

Wenn du identische Werte für pos nicht verbietest, solltest du auf jedenfall einen Index über die pos-Spalte anlegen. Das beschleunigt Abfragen und updates auf der Spalte (Datenbank muss nicht erst sortieren).
 
Zuletzt bearbeitet:
So hier der kürzere Code mit dem es unterhalb einer Sekunde klappt:

Code:
function freeposition($ID, $pos, $tab)
   {
   if($ID == "NULL")
      {
      $primaryquery=
      'SELECT `PRIMARY` from '.$tab.' WHERE `position` = '.$pos;
         $result = mysql_query($primaryquery) or die("Anfrage fehlgeschlagen: " . mysql_error());
         $line = mysql_fetch_row($result);
      
      if(!isset($line[0]))
         {
         return "done";
         }
      else
         {
         $suchpos = $pos - 1;
         $query = 'UPDATE '.$tab.' SET `position`=`position` + 1 WHERE `position` > '.$suchpos.' ORDER BY `position` DESC';
         $result = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());
         return 'done';
         }
      }
   
   else
   {
   if(isset($ID)&&isset($pos)&&isset($tab))
      {
         $primaryquery=
         'SELECT `position` from '.$tab.' WHERE `PRIMARY` = '.$ID;
         $result = mysql_query($primaryquery) or die("Anfrage fehlgeschlagen: " . mysql_error());
         $line = mysql_fetch_row($result);
         global $oldpos;
         $oldpos = $line[0];
         if($oldpos == $pos)
            {
            return 'done';
            }
         
         elseif($oldpos < $pos)
            {
            $query = 'UPDATE '.$tab.' SET `POSITION` = 99999 WHERE `PRIMARY` = '.$ID;
            $result = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());

            $query = 'UPDATE '.$tab.' SET `position`=`position` - 1 WHERE `position` BETWEEN '.$oldpos.' AND '.$pos.' ORDER BY `position` ASC';
            $result = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());

            $query = 'UPDATE '.$tab.' SET `POSITION` = '.$pos.' WHERE `PRIMARY` = '.$ID;
            $result = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());
            return 'done';
            }

         elseif($pos < $oldpos)
            {
            $query = 'UPDATE '.$tab.' SET `POSITION` = 99999 WHERE `PRIMARY` = '.$ID;
            $result = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());

            $query = 'UPDATE '.$tab.' SET `position`=`position` + 1 WHERE `position` BETWEEN '.$pos.' AND '.$oldpos.' ORDER BY `position` DESC';
            $result = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());

            $query = 'UPDATE '.$tab.' SET `POSITION` = '.$pos.' WHERE `PRIMARY` = '.$ID;
            $result = mysql_query($query) or die("Anfrage fehlgeschlagen: " . mysql_error());
            return 'done';
            }
      }

   else
      {
      Print "Nicht genug Variablen für die Funktion sub_position($ID, $pos, $tab) übergeben!<br>";
      Print 'ID = '.$ID.' Position = '.$pos.' Tabelle = '.$tab;
      exit;
      }
   }
   #Print '<br>Orderposition:';
   orderposition($tab);
   return 'done';
   }
 
Zurück
Oben