SQL Выберите: Обновить, если существует, Вставить, если нет - Сравнение части даты?
-
19-08-2019 - |
Вопрос
Мне нужно обновить запись в базе данных со следующими полями
[ID] int (AutoIncr. PK)
[ScorerID] int
[Score] int
[DateCreated] smalldatetime
Если для текущей даты существует запись (должна быть проверена только часть даты, а не время) и заданный счетчик, я бы хотел обновить значение оценки для этого парня и для этого дня. Если у бомбардира на сегодня нет записи, я бы хотел создать новую.
Я получаю седые волосы, пытаясь понять, как поместить это в один (это возможно?) SQL-оператор. Кстати, я использую базу данных MSSQl и метод ExecuteNonQuery()
для выдачи запроса.
Решение
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
Другие советы
Другие ребята рассмотрели совместимые с 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/ ан-нас / библиотека / 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
Используйте возвращаемое значение процедуры, чтобы получить новый 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;
Кто-то может обнаружить, что это связано со статьей в решениях для ВСТАВИТЬ ИЛИ ОБНОВИТЬ на 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