SQL Выберите: Обновить, если существует, Вставить, если нет - Сравнение части даты? - PullRequest
6 голосов
/ 04 декабря 2008

Мне нужно обновить запись в базе данных со следующими полями

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

Если существует запись для сегодняшней даты (должна быть проверена только часть даты, а не время) и заданного счетчика, я бы хотел обновить значение оценки для этого парня и для этого дня. Если у бомбардира нет записи на сегодня, я бы хотел создать новую.

Я получаю седые волосы, пытаясь понять, как выразить это в одном (это возможно?) SQL-выражении. Кстати, я использую базу данных MSSQl и метод ExecuteNonQuery() для выдачи запроса.

Ответы [ 4 ]

16 голосов
/ 04 декабря 2008
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 голосов
/ 04 декабря 2008

Другие ребята рассмотрели совместимые с T-SQL / 2005 подходы (и более ранние). Я просто хотел добавить, что если вам повезло работать с 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 голос
/ 20 сентября 2013

Для случая, когда требуется обновить или вставить все значения сразу, а не только для одной записи, я использовал этот фрагмент

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;

Кто-то может обнаружить, что это связано со статьей на Решения для ВСТАВКИ И ОБНОВЛЕНИЯ на 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
1 голос
/ 04 декабря 2008
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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...