2008-12-04 10 views
6

J'ai besoin de mettre à jour un enregistrement dans une base de données avec les champs suivantsSélection SQL: Mise à jour si existe, Insérer si non - Avec comparaison de la date?

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

Si un enregistrement existe pour la date d'aujourd'hui (seule la partie de date doit être vérifiée, pas le temps) et un marqueur donné, je tiens à mettre à jour la valeur du score pour ce gars et ce jour. Si le marqueur n'a pas de record pour aujourd'hui, j'aimerais en créer un nouveau.

Je commence à avoir des cheveux gris essayant de comprendre comment mettre ceci en une seule instruction sql (est-ce possible?). En passant, j'utilise une base de données MSSQl et la méthode ExecuteNonQuery() pour lancer la requête.

+0

Quelle version de SQL Server utilisez-vous? – RobS

Répondre

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 

Utilisez la valeur de retour de la procédure pour saisir la nouvelle 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

Les autres types ont couvert 2005 (et avant) compatible T-SQL/approbaches. Je voulais juste ajouter que si vous avez la chance de travailler avec SQL Server 2008, vous pouvez profiter de la nouvelle instruction Merge (parfois appelée Upsert).

J'ai eu du mal à trouver une entrée de blog ou un article qui l'explique davantage, mais je l'ai trouvé plutôt (1) helpful entry. L'entrée MSDN officielle est (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

Pour le cas où l'on souhaite mettre à jour ou d'insérer toutes les valeurs à la fois, non seulement pour un enregistrement que j'utilisé cet extrait

1ère manche du script de mise à jour

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

faire ensuite le script d'insertion

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; 

Espérons que quelqu'un a trouvé cela utile.

L'équivalent de cela dans MySql (dans certains cas) est quelque chose comme ceci:

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

Quelqu'un peut trouver que cela est lié à l'article à Solutions for INSERT OR UPDATE on SQL Server

Version mise à jour à l'aide 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 
Questions connexes