2008-12-04 13 views
6

Tengo que actualizar un registro en una base de datos con los siguientes camposSQL Select: Actualizar si existe, Insert if if not - ¿Con la comparación de partes de fechas?

[ID] int (AutoIncr. PK) 
[ScorerID] int 
[Score] int 
[DateCreated] smalldatetime 

Si existe un registro de la fecha de hoy (sólo la parte de fecha debe ser verificada, no es el momento) y un anotador dado, que había desea actualizar el valor del puntaje para este tipo y este día. Si el anotador no tiene un registro para hoy, me gustaría crear uno nuevo.

Me estoy poniendo canoso tratando de entender cómo poner esto en una sola declaración SQL (¿es esto posible?). Por cierto, estoy usando una base de datos MSSQl y el método ExecuteNonQuery() para emitir la consulta.

+0

¿Qué versión de SQL Server estás usando? – RobS

Respuesta

16
IF EXISTS (SELECT NULL FROM MyTable WHERE ScorerID = @Blah AND CONVERT(VARCHAR, DateCreated, 101) = CONVERT(VARCHAR, GETDATE(), 101)) 
    UPDATE MyTable SET blah blah blah 
ELSE 
    INSERT INTO MyTable blah blah blah 
1
CREATE PROCEDURE InsertOrUpdateScorer(@ScorerID INT, @Score INT) 
AS 
BEGIN 
    IF EXISTS (
    SELECT 1 
    FROM Scorer 
    WHERE ScorerID = @ScorerID AND DATEDIFF(dd, GETDATE(), DateCreated) = 0 
) 
    BEGIN 
    UPDATE 
     Scorer 
    SET 
     Score = @Score 
    WHERE 
     ScorerID = @ScorerID 

    RETURN @ScorerID 
    END 
    ELSE 
    BEGIN 
    INSERT 
     Scorer 
     (ScorerID, Score, DateCreated) 
    VALUES 
     (@ScorerID, @Score, GETDATE()) 

    RETURN SCOPE_IDENTITY() 
    END 
END 

Utilice el valor de retorno del procedimiento para agarrar el nuevo ScorerId.

SqlCommand UpdateScorer = New SqlCommand("InsertOrUpdateScorer", DbConn); 
UpdateScorer.CommandType = CommandType.StoredProcedure; 

SqlParameter RetValue = UpdateScorer.Parameters.Add("RetValue", SqlDbType.Int); 
RetValue.Direction = ParameterDirection.ReturnValue; 

SqlParameter Score = UpdateScorer.Parameters.Add("@Score", SqlDbType.Int); 
Score.Direction = ParameterDirection.Input; 

SqlParameter ScorerId = UpdateScorer.Parameters.Add("@ScorerID", SqlDbType.Int); 
ScorerId.Direction = ParameterDirection.Input; 

Score.Value = 15; // whatever 
ScorerId.Value = 15; // whatever 

UpdateScorer.ExecuteNonQuery(); 
Console.WriteLine(RetValue.Value); 
3

Los otros tipos han cubierto los T-SQL/apprroaches compatibles de 2005 (y anteriores). Solo quería agregar que si tiene la suerte de estar trabajando con SQL Server 2008, podría aprovechar la nueva declaración Merge (a veces referida como Upsert).

Tuve problemas para encontrar una entrada en el blog o un artículo que lo explicase más, pero encontré esto más bien (1) helpful entry. La entrada oficial de MSDN es (2) here.

(1) [http://www.sqlservercurry.com/2008/05/sql-server-2008-merge-statement.html]
(2) [http://msdn.microsoft.com/en-us/library/bb510625.aspx]

1

Para el caso cuando se desea actualizar o insertar todos los valores de una vez, no sólo para un registro que utiliza este fragmento

primera ejecución del script de actualización

UPDATE Table1 
SET OPIS = T1.OPIS 
FROM 
    Table1 AS T 
INNER JOIN 
    Table2 AS T1 
    ON 
     T.col = T1.col; 

Después, realice la secuencia de comandos de inserción

INSERT INTO Table1 
SELECT * FROM 
    (
     SELECT T1.* Table2 AS T1 
     LEFT JOIN Table1 AS T2 ON (T2.col = T1.col) 
     WHERE T2.col IS NULL 
    ) AS T; 

Espero que alguien haya encontrado esto útil.

El equivalente de esto en MySQL (en algunos casos) es algo como esto:

 
INSERT INTO table (a,b,c) VALUES (1,2,3) 
    ON DUPLICATE KEY UPDATE c=c+1; 

Alguien puede encontrado que esto está relacionado con el artículo en Solutions for INSERT OR UPDATE on SQL Server

Versión actualizada usando MERGE (Transact-SQL):

DECLARE @USER_ID AS INT=76; 
DECLARE @TYPE AS NVARCHAR(MAX)='set.global'; 
DECLARE @FKEY AS NVARCHAR(MAX)='21'; 
DECLARE @DATA AS NVARCHAR(MAX)='test'; 

     begin tran 
      MERGE UserData 
      USING (SELECT @USER_ID, @TYPE, @FKEY, @DATA) AS Source([UserId], [Type], [FKey], [Data]) 
      ON (UserData.[UserId] = Source.[UserId] AND UserData.[Type] = Source.[Type] AND (UserData.[FKey] = Source.[FKey] OR (Source.[FKey] IS NULL AND UserData.[FKey] IS NULL))) 
      WHEN MATCHED 
      THEN 
       UPDATE SET [Data] = Source.[Data] 
      WHEN NOT MATCHED BY TARGET THEN 
       INSERT 
          ([UserId] 
          ,[Type] 
          ,[FKey] 
          ,[Data]) 
        VALUES 
          (Source.[UserId] 
          ,Source.[Type] 
          ,Source.[FKey] 
          ,Source.[Data]); 

     commit tran 
Cuestiones relacionadas