1

I'm trying to write a script that can be used to restore permissions to stored procedures after our merge replication snapshot agent completes applying snapshot to subscribers. This SQL needs to be somewhat dynamic.

Currently, I'm selecting a list of all our stored procedures and inserting them into a temporary table along with string statements for "Granting" permissions. I'm attempting to loop through all the rows on that table, executing the statements one by one using EXEC() command. I keep getting the error

Only one expression can be specified in the select list when the subquery is not introduced with EXISTS

but my SQL statements look like they should be fine. Maybe I'm not understanding how WHILE works in SQL Server.

Here is my code:

BEGIN
CREATE TABLE sqltemp (id int IDENTITY(1, 1) , Stmt1 varchar(max), Stmt2 varchar(max),  Stmt3 varchar(max))

INSERT INTO sqltemp 
   SELECT 
      'GRANT EXECUTE ON OBJECT::' as Stmt1, name as Stmt2, 'TO edoc_only_execute' as Stmt3
   FROM sys.sysobjects
   WHERE 
      type = 'P' AND name NOT LIKE 'MSMerge%'

DECLARE @counter int = 1
WHILE (@counter < (SELECT COUNT(*) FROM sqltemp))
BEGIN
    DECLARE @sqlrun varchar(max)
    SET @sqlrun = (SELECT Stmt1, Stmt2, Stmt3 FROM sqltemp WHERE id = @counter)
    EXEC(@sqlrun)
    SET @counter = @counter + 1
END
END
GO
DROP TABLE sqltemp

Two questions:

  1. How can I accomplish executing the above script for each item in my temporary table?

  2. Is there a better way of writing a script to restore permissions for each stored procedure in my database after the snapshot is applied (Note: I must be able use SQL system tables to pull stored procedure names)?

0

3 Answers 3

3

You can't say

SET @sqlrun = (SELECT Stmt1, Stmt2, Stmt3 FROM sqltemp WHERE id = @counter)

You will have to concatenate them

SELECT @sqlrun = Stmt1 +' '+ Stmt2 +' '+ Stmt3 FROM sqltemp WHERE id = @counter

A better solution might be?

GRANT EXEC TO edoc_only_execute
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks...curious tho. Further explanation as to why my SET @sqlrun = (SELECT ....) was not acceptable to sql server? Just want to understand so I dont make same mistake again, and follow best practice.
@Encryption - variables in SQL Server are Scalars, they can only contain a single value of a single datatype. The alternative is to use a table variable, but that doesn't get you anywhere in this case. So, you either need to push the three values into three different variables, or concatenate them so they can go into one single variable.
So using SELECT @@sql was providing a one string where SET @SQL was not providing a string type?
2

Corrected query for you first question

    BEGIN
    CREATE TABLE sqltemp (id int IDENTITY(1, 1) , Stmt1 varchar(max), Stmt2 varchar(max),  Stmt3 varchar(max))

    INSERT INTO sqltemp SELECT 'GRANT EXECUTE ON OBJECT::' as Stmt1, name as Stmt2, 'TO edoc_only_execute' as Stmt3
                        FROM sys.sysobjects
                        WHERE type = 'P' AND name NOT LIKE 'MSMerge%'

    DECLARE @counter int = 1
    WHILE (@counter < (SELECT COUNT(*) FROM sqltemp))
    BEGIN
        DECLARE @sqlrun varchar(max)
        SELECT @sqlrun = Stmt1 + Stmt2 +' '+ Stmt3 FROM sqltemp WHERE id = @counter
        PRINT @sqlrun
        EXEC(@sqlrun)
        SET @counter = @counter + 1
    END
    END

Comments

0

@010001100110000101110010011010 and @podiluska beat me to it, but...

SELECT COUNT(*) FROM sqltemp

outside of the while:

SET @end = SELECT COUNT(*) FROM sqltemp
WHILE (@counter < @end)
    ...

No need to re-calculate the end condition for each loop iteration.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.