SQL Server 2005 de uitvoering van MySQL REPLACE INTO?

stemmen
73

MySQL heeft dit ongelooflijk nuttig nog properitary REPLACE INTOSQL Commando.

Kan dit gemakkelijk worden geëmuleerd in SQL Server 2005?

Het starten van een nieuwe transactie, het doen van een Select()en vervolgens UPDATEof INSERT IGNORE en COMMITis altijd een beetje een pijn, vooral wanneer het doen van het in de aanvraag en daarom altijd het houden van 2 versies van de verklaring.

Ik vraag me af of er is een eenvoudige en universele manier om een dergelijke functie in SQL Server 2005 uit te voeren?

De vraag is gesteld op 01/08/2008 om 23:13
bron van user
In andere talen...                            


4 antwoorden

stemmen
20

De functionaliteit die u zoekt is van oudsher een upsert genoemd. Minstens weten hoe het heet zou kunnen helpen vinden wat u zoekt.

Ik denk niet dat SQL Server 2005 heeft geen grote manieren om dit te doen. 2008 introduceert de MERGE statement dat kan worden gebruikt om dit te bereiken, zoals getoond in: http://www.databasejournal.com/features/mssql/article.php/3739131 of http://blogs.conchango.com/davidportas/archive/ 2007/11/14 / SQL-Server 2008-MERGE.aspx

Merge was beschikbaar in de beta van 2005, maar ze verwijderd uit in de definitieve versie.

antwoordde op 01/08/2008 om 23:22
bron van user

stemmen
15

Wat de upsert / merge doet is iets om het effect van ...

IF EXISTS (SELECT * FROM [Table] WHERE Id = X)
   UPDATE [Table] SET...
ELSE
   INSERT IGNORE  INTO [Table]

Dus hopelijk de combinatie van die artikelen en deze pseudo-code kunnen dingen in beweging.

antwoordde op 01/08/2008 om 23:31
bron van user

stemmen
53

Dit is iets dat me ergert over MSSQL ( rant op mijn blog ). Ik wens MSSQL ondersteund upsert.

@ Dillie-O's code is een goede manier bij oudere SQL versies (1 stem), maar het is nog steeds in principe twee IO operaties (het existsen dan is het updateof insert)

Er is een iets betere manier op deze post , in principe:

--try an update
update tablename 
set field1 = 'new value',
    field2 = 'different value',
    ...
where idfield = 7

--insert if failed
if @@rowcount = 0 and @@error = 0
    insert into tablename 
           ( idfield, field1, field2, ... )
    values ( 7, 'value one', 'another value', ... )

Dit vermindert het aan één IO operaties als het een update, of twee als een insert.

MS SQL2008 introduceert mergeuit de SQL: 2003 norm:

merge tablename as target
using (values ('new value', 'different value'))
    as source (field1, field2)
    on target.idfield = 7
when matched then
    update
    set field1 = source.field1,
        field2 = source.field2,
        ...
when not matched then
    insert ( idfield, field1, field2, ... )
    values ( 7,  source.field1, source.field2, ... )

Nu is het eigenlijk gewoon een IO operatie, maar verschrikkelijk code :-(

antwoordde op 15/08/2008 om 13:50
bron van user

stemmen
9

Ik schreef een blog post over dit probleem .

De bottom line is dat als je wilt goedkoop updates ... en u wilt veilig voor gelijktijdige gebruik te zijn. proberen:

update t
set hitCount = hitCount + 1
where pk = @id

if @@rowcount < 1 
begin 
   begin tran
      update t with (serializable)
      set hitCount = hitCount + 1
      where pk = @id
      if @@rowcount = 0
      begin
         insert t (pk, hitCount)
         values (@id,1)
      end
   commit tran
end

Op deze manier heb 1 bewerking voor updates en een maximum van 3 bewerkingen voor inserts. dus, als u over het algemeen dit bijwerkt is een veilige goedkope optie.

Ik zou ook heel voorzichtig zijn niet aan iets dat onveilig is voor gelijktijdige gebruik te gebruiken. Het is echt gemakkelijk om de primaire sleutel schendingen te krijgen of dubbele rijen in de productie.

antwoordde op 21/09/2008 om 23:05
bron van user

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more