2008-08-01 11 views
69

MySQL tiene este increíblemente útil pero apropiado comando REPLACE INTO SQL.Implementación SQL Server 2005 de MySQL REPLACE INTO?

¿Se puede emular fácilmente en SQL Server 2005?

Inicio de una nueva transacción, haciendo un Select() y luego o bien UPDATE o INSERT y COMMIT es siempre un poco de dolor, especialmente cuando se trabaja en la aplicación y por lo tanto siempre mantener 2 versiones de la declaración.

Me pregunto si hay una manera fácil y universal de implementar tal función en SQL Server 2005?

Respuesta

53

Esto es algo que me molesta acerca de MSSQL (rant on my blog). Deseo que MSSQL sea compatible con upsert.

@ código de Dillie-O es una buena manera en las versiones de SQL mayores (1 voto), pero sigue siendo básicamente dos operaciones de IO (el exists y luego el update o insert)

hay una manera un poco mejor en this post, básicamente:

--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', ...) 

Esto reduce a una operación IO si se trata de una actualización, o dos si una inserción.

MS SQL2008 introduce merge del SQL: 2003 estándar:

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, ...) 

Ahora no deja de ser una operación IO, pero el código horrible :-(

+0

Genial, gracias! Guarda la selección y, a menudo, ni siquiera necesita una transacción de Teran en situaciones donde puedo estar seguro de que entre la actualización y la inserción "mi", no hay otra inserción para esa tecla. –

+1

@Michael Será mejor que tenga un índice único en esta tabla y que maneje errores clave duplicados si va a utilizar esta solución. –

+3

@Keith Su declaración de fusión no funciona. 'MERGE' no admite la cláusula' WHERE', tiene que volver a escribir eso usando 'USING' y' ON'. Además, a menos que agregue 'WITH (HOLDLOCK)', hay una carrera y podría suceder un 'INSERT' concurrente, con uno de ellos fallando debido al choque de claves. –

19

La funcionalidad que está buscando se llama tradicionalmente UPSERT. Al menos saber cómo se llama puede ayudarlo a encontrar lo que está buscando.

No creo que SQL Server 2005 tenga ninguna buena manera de hacerlo. 2008 introduce la declaración MERGE que se puede usar para lograr esto como se muestra en: http://www.databasejournal.com/features/mssql/article.php/3739131 o http://blogs.conchango.com/davidportas/archive/2007/11/14/SQL-Server-2008-MERGE.aspx

Merge estuvo disponible en la versión beta de 2005, pero lo eliminaron en la versión final.

15

Lo que el upsert/fusión está haciendo es algo en el sentido de ...

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

Así que espero que la combinación de esos artículos y esto pseudo código puede desbloquear la situación.

9

me escribió una blog post about this issue

El. El resultado final es que si quieres actualizaciones baratas ... y quieres estar seguro para el uso simultáneo. Prueba:

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 

De esta manera tiene 1 operación para actualizaciones y un máximo de 3 operaciones para inserciones. Entonces, si generalmente está actualizando, esta es una opción segura y económica.

También tendría mucho cuidado de no utilizar nada que no sea seguro para uso concurrente. Es muy fácil obtener violaciones de clave primaria o filas duplicadas en producción.

Cuestiones relacionadas