Question

I need to update a record in a database with the following fields

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

If a record exists for todays date (only the date portion should be checked, not the time) and a given scorer, I'd like to update the score value for this guy and this day. If the scorer doesn't have a record for today, I'd like to create a new one.

I'm getting grey hair trying to figure how to put this into a single (is this possible?) sql statement. By the way I'm using an MSSQl database and the ExecuteNonQuery() method to issue the query.

Was it helpful?

Solution

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

OTHER TIPS

The other guys have covered 2005 (and prior) compatible T-SQL/apprroaches. I just wanted to add that if you are lucky enough to be working with SQL Server 2008, you could take advantage of the new Merge (sometimes referred to as Upsert) statement.

I had trouble finding a blog entry or article which explains it further, but I did find this rather (1) helpful entry. The official MSDN entry is (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]

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

Use the return value of the procedure to grab the new 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);

For case when is desired to update or insert all values at once, not only for one record I used this snippet

1st run the update script

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

Then do the insert script

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;

Hope that somebody found this useful.

The equivalent of this in MySql (in some cases) is something like this:

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

Somebody can found that this is related to the article at Solutions for INSERT OR UPDATE on SQL Server

Updated version using 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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top