SQL Select: Actualizar si existe, Insertar si no, ¿con comparación de parte de fecha?

StackOverflow https://stackoverflow.com/questions/340366

  •  19-08-2019
  •  | 
  •  

Pregunta

Necesito actualizar un registro en una base de datos con los siguientes campos

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

Si existe un registro para la fecha de hoy (solo se debe verificar la parte de la fecha, no la hora) y un anotador dado, me gustaría actualizar el valor de puntaje para este tipo y este día. Si el anotador no tiene un registro para hoy, me gustaría crear uno nuevo.

Tengo canas tratando de imaginar 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.

¿Fue útil?

Solución

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

Otros consejos

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

Tuve problemas para encontrar una entrada de blog o un artículo que lo explique más, pero encontré esto más bien (1) entrada útil . La entrada oficial de MSDN es (2) aquí.

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

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 obtener 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);

Para el caso en que se desea actualizar o insertar todos los valores a la vez, no solo para un registro, utilicé este fragmento

Primero ejecuta el script de actualización

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

Luego haz el script 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 encuentre 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 descubrir que esto está relacionado con el artículo en Soluciones para INSERTAR O ACTUALIZAR en SQL Server

Versión actualizada con 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top