Wert in jeder Zeile um 1 erhöhen, inkrementieren

Hallo, ich habe noch nicht so viele Kenntnisse in der PL/pgSQL Programmierung und stehe vor einem kleinen Problem.

Ich möchte in einer Tabelle einen Update Befehl machen und in einer Spalte den jeweiligen Datensatz-Wert immer um 1 erhöhen (ausgehend vom bisherigen Maximalwert) wenn gewisse Bedinungen erfüllt sind. Das soll dann am Ende mit Hilfe einer Funktion/Prozedur geschehen. Den Update Befehl hab ich wie folgt erstellt:

update tabelle
SET wert= (SELECT MAX(wert) FROM tabelle) +1
where wert IS NULL AND wert2 is NOT NULL;

Im Prinzip soll, wenn die Bedingung erfüllt ist, nach dem Maximum des Wertes “wert” in der Spalte gesucht werden und jeder Datensatz dann um 1 erhöht werden. Aber mit diesem Befehl erreiche ich ja nur das alle Werte am ende den selben um 1 erhöhten Wert haben. Ich möchte aber, dass jede einzelne Zeile um 1 erhöht wird (zB. max wert:5, dann+1=6,+1=7,+1=8,…).
Ist wahrscheinlich einfach zu lösen, finde aber nicht die Lösung :see_no_evil:

Vielen Dank für Eure Hilfe!

Ich würde die neuen Werte mit Window Funktionen berechnent und das Ergebnis dann verwenden um die Tabelle zu ändern:

with new_numbers as (
  select pk_spalte, max(wert) over () + row_number() over () as x
  from tabelle t
  where t.wert is null
    and t.wert2 is not null  
)
update tabelle t
  set wert = n.x
from new_numbers n 
where n.pk_spalte = t.pk_spalte

Auf den maximal wert wird einfach eine sich ständig erhöhende Zahl addiert. Und das Ergebnis wird dann im UPDATE verwendet.

das klingt konzeptionell schlecht durchdacht. Da ist die Frage, in welcher Reihenfolge die Datensätze so neu nummeriert werden sollen. Dann, was passiert, wenn später Datensätze geändert, gelöscht oder eingefügt werden?

test=# select * from texs89;
 id | wert 
----+------
  1 |     
  2 |    7
  3 |     
  4 |     
  5 |     
(5 rows)

test=*# with x as (select id, max(wert) over(), row_number() over () from texs89) select * from x;
 id | max | row_number 
----+-----+------------
  1 |   7 |          1
  2 |   7 |          2
  3 |   7 |          3
  4 |   7 |          4
  5 |   7 |          5
(5 rows)

test=*# with x as (select id, max(wert) over(), row_number() over () from texs89) update texs89 set wert = max+row_number from x where texs89.id=x.id;
UPDATE 5
test=*# select * from texs89;
 id | wert 
----+------
  1 |    8
  2 |    9
  3 |   10
  4 |   11
  5 |   12
(5 rows)

Mal als Idee - ähnlich wie @castorp eben auch :wink:

Vielen Dank schonmal für die schnellen Antworten, ich glaube ich hab gerade ebenfalls eine Fast-Lösung gefunden. Im Prinzip kann man ja einen Counter i immer um eins erhöhen:

CREATE OR REPLACE FUNCTION generate_nr()
    RETURNS BOOLEAN LANGUAGE plpgsql SECURITY DEFINER AS $$
    
    DECLARE
    i int=(SELECT MAX(wert)+1 FROM tabelle);
    BEGIN
    update tabelle
    SET wert=i, i=i+1
    where wert IS NULL AND wert2 is NOT NULL;
    RETURN FOUND;

END;
$$;

Aber irgendwie ist es so nicht ganz korrekt:
ERROR: FEHLER: Spalte »i« von Relation »tabelle« existiert nicht
LINE 2: SET wert=i, i=i+1

Du kannst mit einem Update nur Spalten einer Tabelle verändern, aber nicht die Werte von Variablen

update tabelle
    SET wert=i, i=i+1

PostgreSQL und jeder andere DB auch, sucht jetzt in der Tabelle tabelle, die Spalte i.

Ich würde auch die Vorgehensweise von @castorp verwenden.

Gruß frastr

Ich hatte die Variante von hier:
https://stackoverflow.com/questions/13629382/update-int-column-in-table-with-unique-incrementing-values

Hab es aber jetzt so wie castorp es empfohlen hat gemacht und es funktioniert, danke :slight_smile:!

Die Antwort ist für SQL Server - so ziemlich die einzige Datenbank bei der es keine klare Trennung zwischen prozeduralen Code (PL/pgSQL) und der Abfragesprache (SQL) gibt. Deswegen darf man da Variablen und prozedurale Sprachkonstrukte munter mit SQL mischen.