On Feb 27, 2013, at 2:53 PM, James K. Lowden <jklow...@schemamania.org> wrote:
> On Mon, 25 Feb 2013 23:54:23 +0100 > anydacdev anydacdev <anydac...@gmail.com> wrote: > >> I was wondering what is SQLite's equivalent to: >> >> MERGE INTO x TGT >> USING (SELECT NAME, KEY FROM y) SRC >> ON (TGT.key = SRC.key) >> WHEN MATCHED THEN >> UPDATE SET TGT.NAME = NAME >> WHEN NOT MATCHED THEN >> INSERT (TGT.NAME) VALUES (SRC.NAME) > > begin transaction; > update tgt > set name = (select name from src where tgt.key = src.key) > where exists ( > select 1 from src > where src.key = tgt.key > ); > -- check for error > insert into tgt (name) > select name from src > where not exists ( > select 1 from tgt > where tgt.key = src.key > ); > -- check for error > commit transaction; > > It's only close, not equivalent, because MERGE is atomic: here src and > tgt could change between UPDATE and INSERT. That you'll have to deal > with using timestamps or some form of advisory locking. As SQLite can only have one writer at the time, perhaps a 'begin immediate transaction;' will deal with that. Regarding the 'update' part, I'm not sure how unwieldy this will grow when introducing more columns, and more feature, such as the ability to update only rows which have effective changes. So, all in all, one may end up with the following: --8<-- begin immediate transaction; -- assume 'source' is populated somehow, somewhere, before hand… update target set value1 = ( select value1 from source where source.key = target.key ), value2 = ( select value2 from source where source.key = target.key ), value3 = ( select value3 from source where source.key = target.key ), value4 = ( select value4 from source where source.key = target.key ) where exists ( select 1 from source where source.key = target.key and ( coalesce( source.value1, '-' ) != coalesce( target.value1, , '-' ) or coalesce( source.value2, '-' ) != coalesce( target.value2, , '-' ) or coalesce( source.value3, '-' ) != coalesce( target.value3, , '-' ) or coalesce( source.value4, '-' ) != coalesce( target.value4, , '-' ) ) ); insert into target ( key, value1, value2, value3, value4 ) select key, value1, value2, value3, value4 from source where not exists ( select 1 from target where target.key = source.key ); commit transaction; -->8-- Quite a mouthful. Not to even mention all these scalar queries and multiple passes over both source and target. Compare that to an hypothetical merge statement: merge into target using ( select key, value1, value2, value3, value4 from source ) source on ( target.key = source.key ) when matched then update set target.value1 = source.value1, target.value2 = source.value2, target.value3 = source.value3, target.value4 = source.value4 where coalesce( target.value1, '-' ) != coalesce( source.value1, , '-' ) or coalesce( target.value2, '-' ) != coalesce( source.value2, , '-' ) or coalesce( target.value3, '-' ) != coalesce( source.value3, , '-' ) or coalesce( target.value4, '-' ) != coalesce( source.value4, , '-' ) when not matched then insert ( key, value1, value2, value3, value4 ) values ( source.key, source.value1, source.value2, source.value3, source.value4 ); Another major benefit of merge is that the 'using' clause can be any query. No need for a preexisting source as for the update/insert scenario above. Alternatively, this could be all turned inside out, and dealt with programmatically. Pseudo code: for row in ( select source.key as skey, source.value1 as svalue1, source.value2 as svalue2, source.value3 as svalue3, source.value4 as svalue4, target.key as tkey, target.value1 as tvalue1, target.value2 as tvalue2, target.value3 as tvalue3, target.value4 as tvalue4 from source left join target on target.key = source.key ) loop if row.target is null then insert into target ( key, value1, value2, value3, value4 ) values ( row.skey, row.svalue1, row.svalue2, row.svalue3, row.svalue4 ); elseif coalesce( row.tvalue1 ) != coalesce( row.svalue1, , '-' ) or coalesce( row.tvalue2, '-' ) != coalesce( row.svalue1, , '-' ) or coalesce( row.tvalue3, '-' ) != coalesce( row.svalue1, , '-' ) or coalesce( row.tvalue4, '-' ) != coalesce( row.svalue1, , '-' ) then update target set value1 = row.svalue1, value2 = row.svalue2, value3 = row.svalue3, value4 = row.svalue4 where key = row.skey; end; end loop; Not that pleasing either. Sigh... _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users