UPDATE Befehl vergleicht nur erstes Vorkommen einer Bedingung

Hallo an alle,

ich benötige eventl. einen anderen Blickwinkel auf meinen Update-Befehl. Muss ich vielleicht mit Arrays arbeiten? Hier mein Problem:
Tabelle 1:
id; nr; blb; …
1; 1001; 3002034
2; 1001; 3002035
3; 1002; 3002040
4; 1003; 3002042
5; 1001; NULL
6; 1001; 3002034
usw.
Tabelle 2:
tab1_nr; ud1; …
1001; NULL
1002; NULL
1003, NULL
usw.

Jetzt wollte ich die blb in ud1 zusammenfügen (als String deklariert), aber irgendwie trägt er nur das erste Vorkommen von nr ein anstatt wie angegeben als Verkettung. Hier meine Anweisung:

update tabelle2 set ud1=(Case When ud1 is NULL Then x.blb ELSE concat(ud1,‘,’,x.blb) END)
from (
select nr, blb from tabelle1 where blb is not Null
group by nr, blb
) x
where tab1_nr=x.nr
;

Gewünschtes Ergebnis sollte sein:
tab1_nr; ud1; …
1001; 3002034, 3002035 ;
usw.
Aktuelles Ergebnis:
tab1_nr; ud1;
1001; 3002034
usw.

Ich hoffe, ich konnte das Problem verständlich darstellen. Vielen Dank vorab!

Ungetestet:

update tabelle2 t2
   set ud1 = (
               select string_agg(blb,',')
                   from tabelle1 t1
                   where t1.nr = t2.tab1_nr
                   );

Im Vorschlag von @frastr fehlt die Where Bedingung.

Beim Concatenieren ist das Ergebnis NULL, sobald ein Teil NULL ist. NULLS müssen also in diesem Fall durch Leerstrings ersetzt werden.

Ob das Dein Problem

trifft, weiß ich nicht, weil ich nicht richtig verstehe, was Du damit meinst.

1 „Gefällt mir“

Im Vorschlag von @frastr fehlt die Where Bedingung.

Beim Concatenieren ist das Ergebnis NULL, sobald ein Teil NULL ist. NULLS müssen also in diesem Fall durch Leerstrings >ersetzt werden.

Das where ist bei string_agg nicht notwendig:

with test(col) as (
    values ('test1')
        ,('test2')
        ,(null)
        ,('test3')
)
select string_agg(col, ',')
    from test;
    string_agg     
-------------------
 test1,test2,test3
(1 Zeile)
1 „Gefällt mir“

Das ist korrekt und auch so dokumentiert

In other words, a target row shouldn’t join to more than one row from the other table(s). If it does, then only one of the join rows will be used to update the target row, but which one will be used is not readily predictable.

Das skalare sub-select von frastr sollte funktionieren, ist aber vermutlich recht langsam. Meistens ist es besser die Aggregation nur einmal zu machen:

update tabelle2 t2
   set ud1 = t.blbs
from ( 
   select nr, string_agg(blb,',') as blbs
   from tabelle1
   group by nr
) t 
where t.nr = t2.tab1_nr
2 „Gefällt mir“

Das skalare sub-select von frastr sollte funktionieren, ist aber vermutlich recht langsam. Meistens ist es besser die Aggregation nur einmal zu machen:

:+1: Korrekt. Danke für den zusätzlichen Hinweis.

Das ist korrekt und auch so dokumentiert

Vielen Dank für den Hinweis!

> update tabelle2 t2
>    set ud1 = t.blbs
> from ( 
>    select nr, string_agg(blb,',') as blbs
>    from tabelle1
>    group by nr
> ) t 
> where t.nr = t2.tab1_nr

Super, vielen Dank! Hat funktioniert :+1:, bis auf eine kleine Anpassung:
...string_agg(distinct blb, ',') ...
da Werte in blb auch doppelt vorkommen können, ich die aber nur einmal aufgezählt haben möchte!

Der Befehl string_agg war mir bisher nicht bekannt :slight_smile: Jetzt bin ich wieder etwas schlauer :pray:

Ja, Du hast Recht, sorry.
Updates ohne Where sind mir immer suspect. Auch wenn nichts schief geht, updated man vielleicht (viel) mehr als nötig, wenn alter Wert und neuer Wert gleich sind.

Dieses Thema wurde automatisch 60 Tage nach der letzten Antwort geschlossen. Es sind keine neuen Antworten mehr erlaubt.