heinetz: SELECT @c := @c + 1

Hallo Forum,

ich habe mal für ein Skript nach einer Möglichkeit gesucht,
eine Spalte neu durchzunummerieren und eine ganz elegante
Lösung per SQL gefunden. Das ging so:

SET @c := -1;  
  
UPDATE  `structure` SET  `d3` = ( SELECT @c := @c + 1 )  
ORDER BY `id`;  

Jetzt benötige ich wieder so etwas. Allerdings ist die
Numerierung etwas komplizierter. So sieht meine Tabelle
im Prinzip aus:

id | d0 | d1 | d2 | d3 |
--------|----|----|----|----|
      1 |  0 |  0 |  0 |  0 |
--------|----|----|----|----|
      2 |  0 |  1 |  0 |  0 |
--------|----|----|----|----|
      3 |  0 |  1 |  1 |  0 |
--------|----|----|----|----|
      4 |  0 |  1 |  1 |  1 |
--------|----|----|----|----|
      5 |  0 |  1 |  1 |  2 |
--------|----|----|----|----|
      6 |  0 |  1 |  1 |  3 |
--------|----|----|----|----|
      7 |  0 |  1 |  2 |  0 |
--------|----|----|----|----|
      8 |  0 |  1 |  2 |  1 |
--------|----|----|----|----|
      9 |  0 |  1 |  2 |  3 |
--------|----|----|----|----|
     10 |  0 |  1 |  2 |  4 |

Eines Vorab:
------------
Die Struktur an sich soll nicht verändert werden und
daher ist eine Diskussion über Sinn oder Unsinn dieses
DB-Layouts überflüssig. Mir ist bewusst, dass man das
anders hätte machen können und wohl auch sollen.

Aber zu den Inhalten:
---------------------
Die Felder d0-d3 stellen Ebenen einer Baumstruktur dar.
Der Wert 0 zeichnet einen Datensatz als Elternelement
aus. Sehen wir uns nur die 'Blätter' also die letzte Ebene
an. Dann ist der Datensatz id=3 Elternelement von 4,5 und
6 und der Datensatz id=7 Elternelement von 8, 9 und 10.
Die Reihenfolge der Kinder von id=3 (4, 5 und 6) ergibt
sich aus deren Werte in d3 also 1, 2, 3.
Die Nummerierung in den Beispieldaten ist zur Zeit korrekt.
Jetzt will ich aber Datensatz id=5 löschen. Dadurch entsteht
eine Lücke und die Nummerierung der verbleibenden Kinder von
id=3 (4 und 6) ist 1, 3.

Mit der SQL-Lösung oben könnte ich die Daten sortieren:

... ORDER BY d0, d1, d2, d3

... den zuvor festgelegten Zähler:

SET @c := -1;

bei jedem Datensatz im 1 hochzählen:

SELECT @c := @c + 1

... und so die gesammte Tabelle im Feld d3 neu durchnummerieren.
Was mir nicht klar ist, ist wie ich dafür sorge, dass immer wenn
in d3 der Wert 0 steht der Zähler wieder auf 0 gesetz wird.

Ich glaube, die Logik ist klar, mir fehlt nur die Systax.

Kann mir dabei jemand helfen ?

danke und beste gruesse,
heinetz

  1. Hallo Forum,

    mein erster Versuch sieht so aus:

    SET @c := 0;  
    UPDATE  `structure` SET  `d3` = ( SELECT IF(`structure`.`d2`=0, @c := 0, @c := @c + 1) )  
    ORDER BY `d0` , `d1` , `d2` , `d3`;
    

    Dazu sei gesagt, dass ich nie mit IF in SQL gearbeitet habe.
    Aber ich gehe davon aus, dass das mit einer MySQL 5.0.45
    funktionieren sollte. Dennoch tritt der ELSE-Fall ein und
    die Tabelle wird vollständig von Anfang bis Ende laufend
    durchnummeriert.

    Ich vermute, die Bedingung kann nicht wahr sein, weil
    structure.d2 an der Stelle unbekannt ist.

    danke fuer Tipps und

    beste gruesse,
    heinetz

    1. Hello,

      SET @c := 0;

      UPDATE  structure SET  d3 = ( SELECT IF(structure.d2=0, @c := 0, @c := @c + 1) )
      ORDER BY d0 , d1 , d2 , d3;

        
      Dazu müsste man jetzt wissen, ob zwischen das (Sub-)Select und das Update andere Queries anderer Prozesse dazwischen passen, oder ob die beiden atomar gebunden sind.  
        
        
        
        
        
      Liebe Grüße aus dem schönen Oberharz  
        
        
      Tom vom Berg  
      ![](http://selfhtml.bitworks.de/Virencheck.gif)  
        
      
      -- 
       ☻\_  
      /▌  
      / \ Nur selber lernen macht schlau  
      <http://bergpost.annerschbarrich.de>
      
      1. Hello,

        Dazu müsste man jetzt wissen, ob zwischen das (Sub-)Select und das Update andere Queries anderer Prozesse dazwischen passen, oder ob die beiden atomar gebunden sind.

        um das zu beantorten, müsste ich es verstehen ;)

        beste gruesse,
        heinetz

      2. Hallo Tom,

        SET @c := 0;

        UPDATE  structure SET  d3 = ( SELECT IF(structure.d2=0, @c := 0, @c := @c + 1) )
        ORDER BY d0 , d1 , d2 , d3;

        
        >   
        > Dazu müsste man jetzt wissen, ob zwischen das (Sub-)Select und das Update andere Queries anderer Prozesse dazwischen passen,  
          
        nein, natürlich nicht. Es ist \*ein\* UPDATE.  
          
        
        > oder ob die beiden atomar gebunden sind.  
          
        Ja. Sonst könntest Du alle Subselects in INSERT, UPDATE oder DELETE in die Tonne treten. Siehe dazu <http://dev.mysql.com/doc/refman/5.0/en/locking-issues.html>.  
          
          
        Freundliche Grüße  
          
        Vinzenz