SQL选择:如果存在则更新,如果不存在则插入 - 带有日期部分比较?

6

我需要更新数据库中以下字段的记录

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

如果今天的日期已存在记录(只需检查日期部分,而不是时间),并且给定的评分人员,则希望更新此人和此日期的得分值。如果评分人员今天没有记录,则希望创建一个新记录。
我正在尝试将此操作放入单个 SQL 语句中,但一直无法成功。顺便提一下,我正在使用 MSSQL 数据库和 ExecuteNonQuery() 方法来发出查询。

你正在使用哪个版本的SQL Server? - RobS
4个回答

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

3
其他人已经涵盖了2005年(及之前)兼容的T-SQL /方法。我只想补充说,如果你很幸运地使用SQL Server 2008,你可以利用新的Merge(有时称为Upsert)语句。
我在寻找进一步解释的博客文章或文章时遇到了麻烦,但我找到了这篇相当(1)有帮助的文章。官方的MSDN条目在(2)这里。 (1)[http://www.sqlservercurry.com/2008/05/sql-server-2008-merge-statement.html]
(2)[http://msdn.microsoft.com/en-us/library/bb510625.aspx]]

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

使用过程的返回值来获取新的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);

1

如果想要一次更新或插入所有值而不仅仅是一个记录,我使用了以下代码:

首先运行更新脚本

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

然后执行插入脚本

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;

希望有人会发现这个有用。

在MySQL中,这个的等效方法(在某些情况下)可能如下:

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

有人可能会认为这与Solutions for INSERT OR UPDATE on SQL Server相关。

使用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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接