Thread: Non-procedural field merging?
I have two tables, foo and foo2: richardh=> select * from foo;a | b ---+-----1 | xxx1 | yyy richardh=> select * from foo2;c | d ---+---1 | And I would like to set d to 'xxxyyy' (i.e. merge entries from b). Of course the following doesn't work because the 'd' seen is the one from before the query starts. richardh=> update foo2 set d = d || foo.b from foo where foo.a=foo2.c; UPDATE 1 richardh=> select * from foo2;c | d ---+-----1 | yyy Now - I can always solve the problem procedurally, merging the values in my application but I was wondering if any of the smarter people on the list have an SQL way of doing it (something with sub-queries?) PS - I realise I might get 'xxxyyy' or 'yyyxxx' without forcing an order but I don't actually care in this case. TIA - Richard Huxton
"Richard Huxton" <dev@archonet.com> writes: > I have two tables, foo and foo2: > richardh=> select * from foo; > a | b > ---+----- > 1 | xxx > 1 | yyy > richardh=> select * from foo2; > c | d > ---+--- > 1 | > And I would like to set d to 'xxxyyy' (i.e. merge entries from b). You could do it with a user-defined aggregate function (initial value '' and transition function ||). I am not sure that aggregates work in an intelligent way in UPDATE --- ie, I am not sure it would work to do update foo2 set d = catenate(foo.b) from foo where foo.a=foo2.c; I seem to recall some discussion concluding that that didn't have very well-defined semantics. But you could do SELECT a, catenate(b) INTO TEMP TABLE t1 FROM foo GROUP BY a; and then update into foo2 from the temp table. > PS - I realise I might get 'xxxyyy' or 'yyyxxx' without forcing an order but > I don't actually care in this case. Check. You don't have any control over the order in which input rows will be presented to an aggregate function. regards, tom lane
From: "Tom Lane" <tgl@sss.pgh.pa.us> [snipped my Q about merging text fields from one table into another] > You could do it with a user-defined aggregate function (initial > value '' and transition function ||). I am not sure that aggregates > work in an intelligent way in UPDATE --- ie, I am not sure it would > work to do > > update foo2 set d = catenate(foo.b) from foo where foo.a=foo2.c; Actually, (to my surprise) it did work. I used: richardh=> create aggregate catenate(sfunc1=textcat, basetype=text, stype1=text, initcond1=''); CREATE richardh=> select a,catenate(b) from foo group by a;a | catenate ---+----------1 | xxxyyy (1 row) Then tried the update - worked with no problem, noting that: richardh=> update foo2 set d = catenate(foo.b) from foo where foo.a=foo2.c; UPDATE 1 richardh=> select * from foo2;c | d ---+--------1 | yyyxxx (1 row) The order is reversed between the select and the update! Important lesson in the relationship between SQL and set theory noted (my college lecturers would be proud of me ;-) > I seem to recall some discussion concluding that that didn't have > very well-defined semantics. I can see how you'd have problems if you were expecting the aggregate to return the same value on each run (a vacuum presumably could reorder the values). In my case, this isn't important. I must admit it didn't occur to me you could create your own aggregates without resorting to C. Shame it's not a standard SQL feature. Thanks Tom - don't know how you find the time to give so much help in the lists. - Richard Huxton