Пожалуйста, смотрите мои комментарии ниже:
CREATE PROCEDURE [dbo].spRecordStudentScore
@StudentNum BIGINT,
@TestID BIGINT,
@DateCompleted DATETIME,
@Score FLOAT
Я вижу, что @Score
определяется как FLOAT
... что будет приблизительным значением.Вы уверены, что не хотите использовать вместо этого DECIMAL
тип?
Кроме того, BIGINT
кажется довольно большим для TestID
или StudentNum
(если StudentNum
действительно не должно бытьVARCHAR
) ... вы уверены, что INT
будет недостаточно?
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Attempt int;
SET @Attempt = 1;
BEGIN
IF NOT EXISTS (SELECT * FROM dbo.tbStudentScores WHERE fdStudent# = @StudentNum AND fdTestID = @TestID AND fdAttempt = @Attempt)
SET @Attempt = 1;
ELSE
SELECT @Attempt = fdAttempt FROM dbo.tbStudentScores WHERE fdStudent# = @StudentNum AND fdTestID = @TestID ORDER BY fdAttempt DESC LIMIT 1
END
Вместо LIMIT 1
вы можете сделать SELECT TOP 1 @Attempt = fdAttempt
...
BEGIN TRANSACTION
BEGIN
IF NOT EXISTS (SELECT * FROM dbo.tbStudentScores WHERE fdStudent# = @StudentNum AND fdTestID = @TestID AND fdDateCompleted = @DateCompleted AND fdScore = @Score)
Запись может фактически проникнуть сюда между проверкой, если она существует, и до ее вставки ... если вам нужно предотвратить это, вам нужно будет использовать сериализуемое чтение ... возможно, с исключительной блокировкой чтения.а также, чтобы предотвратить тупик.Или лучше было бы убедиться, что у вас есть соответствующие уникальные ограничения для таблицы.
INSERT INTO dbo.tbStudentScores
(fdStudent#,
fdTestID,
fdAttempt,
fdDateCompleted,
fdScore)
VALUES (@StudentNum,
@TestID,
@Attempt,
@DateCompleted,
@Score)
END
-- END INSERT INTO dbo.tbStudentScores
Какую версию MS SQL Server вы используете?Если это 2005 или более поздняя версия, вы должны проверить TRY CATCH
блоков для обработки ошибок.
IF @@error <> 0
BEGIN
ROLLBACK TRANSACTION
RETURN 1
END
ELSE
BEGIN
COMMIT TRANSACTION
RETURN 0
END
END
-- END PROCEDURE [dbo].spRecordStudentScore
GO