简体   繁体   中英

Using a stored procedure to (+1 or -1) a value from a table

I have a button event that has to disable itself after a certain number of users is reached.

We are storing the currently accessed user count in the db, and I am trying to create a stored procedure, that when called, will automatically increment the user count on that table.
I am going to create a separate procedure to subtract.

In my mind, I would need to get the current value, add one, then save it in the table, bringing me to this code:

CREATE PROCEDURE procDrRefBooksAddUser 
    -- Add the parameters for the stored procedure here
    @fileId int = NULL,
    @count int = 0,
    @newCount int OUTPUT
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    SELECT UserCount FROM tblDrRefBooks WHERE DrRefBookFileID = @fileId
    SET @count = UserCount

    SET @newCount = @count + 1

    -- Insert statements for procedure here
    UPDATE tblDrRefBooks SET tblDrRefBooks.UserCount = @newCount WHERE DrRefBookFileID = @fileId
END

Unfortunately, I am unable to get it right, coming up with errors such as:

Msg 207, Level 16, State 1, Procedure procDrRefBooksAddUser, Line 17
Invalid column name 'UserCount'

Could someone please tell me where I'm going wrong.

Edit: Update on answer (finally)

My SQL is:

ALTER PROCEDURE [dbo].[procDrRefBooksAddUser] 
    -- Add the parameters for the stored procedure here
    @fileId int = NULL,
    @newCount int OUTPUT
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    -- SET NOCOUNT ON;

    UPDATE tblDrRefBooks
    SET @newCount = UserCount = UserCount + 1
    WHERE DrRefBookFileID = @fileId
    SELECT @newCount AS iden

END

And code behind is:

 using (SqlConnection db = DataConn.SqlConnection())
                {
                    db.Open();
                    SqlTransaction transaction = db.BeginTransaction();

                    try
                    {
                        lbltest.Text = "Starting...";
                       using (SqlCommand acommand =
                            new SqlCommand(
                                "EXEC procDrRefBooksAddUser @fileID, @count",
                                db, transaction) { CommandType = CommandType.Text })
                        {
                            acommand.Parameters.Add(new SqlParameter("@fileID", SqlDbType.Int)).Value = Int32.Parse(location.Value);
                            acommand.Parameters.Add(new SqlParameter("@count", SqlDbType.Int) { Direction = ParameterDirection.Output });

                            using (SqlDataReader rdr = acommand.ExecuteReader())
                            {
                                btnLoad.Text = "Here: " + rdr["iden"];
                            }
                        }

                        transaction.Commit();
                    }
                    catch (Exception ea)
                    {
                        transaction.Rollback();
                        lbltest.Text = ("Insertion Error: " + ea.Message);
                    }
                }

But I get this error: Insertion Error: Invalid attempt to read when no data is present.

SET @count = UserCount 

is incorrect. You can't access columns from previous SELECT statements like that.

You can just do it all in one atomic statement. This increments the column and sets the output parameter with the new value of UserCount.

UPDATE tblDrRefBooks
SET    @newCount = UserCount = UserCount + 1
WHERE  DrRefBookFileID = @fileId 

This avoids race conditions from reading and writing the value in separate operations.

For reference case, it should be like this

SELECT @Count = UserCount FROM tblDrRefBooks WHERE DrRefBookFileID = @fileId
@newCount = @Count + 1

But you can just avoid that and do this instead

UPDATE tblDrRefBooks SET UserCount = UserCount + 1
WHERE 
   DrRefBookFileID = @fileId AND
   UserCount < @MaxUserCount

Update

Notice I added AND UserCount < @MaxUserCount . Your stored procedure might not capture all the count as page refreshes quickly [race condition]. You may have an old @Count value.

  • Make sure the count is only increase if MAX is not reached
  • Just get the count at any point in time with another PROC. Don't do it in the same PROC as for updating count as you can get OLD count value
  • Can have a flag on your table that is SET in the PROC once MAX is reached

Use below code in your procedure :

SELECT @count=UserCount FROM tblDrRefBooks WHERE DrRefBookFileID = @fileId

no need to use temporary variables and use of select query. try this..

UPDATE tblDrRefBooks 
SET tblDrRefBooks.UserCount = UserCount +1 
WHERE DrRefBookFileID = @fileId

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM