【问题标题】:Use database inside a stored procedure在存储过程中使用数据库
【发布时间】:2011-11-17 11:48:31
【问题描述】:

我需要创建一个在多个数据库中创建用户的存储过程。像这样的:

USE [database1]

CREATE USER [userLogin] FOR LOGIN [userLogin]

USE [database2]

CREATE USER [userLogin] FOR LOGIN [userLogin]

由于CREATE USER 语句在当前数据库中完成了他的工作,我需要使用USE 语句在数据库之间进行更改,但它不能在存储过程中使用。

我该怎么做?

【问题讨论】:

    标签: sql-server tsql stored-procedures


    【解决方案1】:

    动态 SQL

    CREATE PROCEDURE spTestProc
    AS
    
    EXEC ('USE [database1]; CREATE USER [userLogin] FOR LOGIN [userLogin]')
    
    EXEC ('USE [database2]; CREATE USER [userLogin] FOR LOGIN [userLogin]')
    GO
    

    【讨论】:

      【解决方案2】:

      SQL Server 为我们提供了一个系统存储过程来执行此操作。我的理解是推荐的方法是使用 sys.sp_grantdbaccess:

      CREATE PROCEDURE usp_CreateTwoUSers
      
      AS
      BEGIN
      
          -- Create a user for a login in the current DB:
          Exec sp_grantdbaccess [userLogin], [name_in_db];
      
          -- Create a user for a login in an external DB:
          Exec ExternalDatabaseName.sys.sp_grantdbaccess [userLogin], [name_in_db];
      
      END
      

      【讨论】:

      • 快速检查表明这些已被弃用msdn.microsoft.com/en-us/library/ms178013.aspx
      • @gbn - 不错的收获。我没有意识到这一点。不过,我回家后会尽快调查。看起来可能需要 CREATE LOGIN 和 CREATE USER 的组合。希望已弃用(但仍然有效)的 sp_grantdbaccess proc 将暂时满足 OP 的需求。
      【解决方案3】:

      我是这样做的:

      Alter Procedure testProc
      @dbName varchar(50)
      As
      declare @var varchar(100)
      set @var = 'Exec(''create table tableName(name varchar(50))'')'    
      Exec('Use '+ @dbName + ';' + @var)
      Exec testProc 'test_db'
      

      【讨论】:

        【解决方案4】:
        CREATE PROCEDURE spTestProc
        AS
        BEGIN
        
        EXECUTE sp_executesql N'USE DB1 SELECT * FROM TABLE1'
        
        
        EXECUTE sp_executesql N'USE DB2 SELECT * FROM Table2'
        
        
        END
        
        exec spTestProc
        

        现在可以了。

        【讨论】:

          【解决方案5】:

          如果您使用EXEC sp_executesql ('query1')EXEC ('query2') 编写动态SQL,这将返回您想要的正确数据库。如果您在动态 SQL 引号或括号之外编写静态 SQL 或查询,它将在 master 上工作(您创建存储过程的位置(默认为 master))。

          CREATE PROCEDURE master.dbo.mysp1
          AS
          
              EXEC ('USE model; SELECT DB_NAME()') -- or sp_executesql N'USE model; SELECT DB_NAME()' 
              --this returns 'model'
          
          GO
          
          
          CREATE PROCEDURE master.dbo.mysp2
          AS
          
              EXEC ('USE model;') -- or sp_executesql N'USE model;'
              SELECT DB_NAME() 
              -- this returns 'master'
          
          GO
          

          【讨论】:

            【解决方案6】:

            需要注意的是,如果你想在EXEC命令中使用单引号,你需要将单引号的数量加倍

            例如

            EXEC ('USE [database1]; select * from Authors where name = ''John'' ')
            

            在此示例中,John 在其前后有 2 个单引号。 此类查询不能使用双引号。

            【讨论】:

              【解决方案7】:

              使用sp_executesql 似乎有效,有关更多信息,请参阅http://msdn.microsoft.com/en-us/library/ms175170.aspx

              我用这个测试过,效果很好:

              CREATE PROCEDURE spTestProc
              AS
              BEGIN
              
              EXECUTE sp_executesql N'USE DB1;'
              
              SELECT * FROM TABLE1
              EXECUTE sp_executesql N'USE DB2;'
              
              SELECT * FROM Table2
              
              END
              
              exec spTestProc
              

              【讨论】:

              • USE 应该只在 sp_executesql 调用的范围内,而不是外部存储过程
              • 正如 gbn 所指出的,USE 命令范围将是使用 sp_executesql 执行的 SQL 的本地范围。
              猜你喜欢
              • 1970-01-01
              • 2011-03-05
              • 2018-05-14
              • 2018-05-15
              • 1970-01-01
              • 2011-12-16
              • 2013-01-31
              • 1970-01-01
              • 2012-07-27
              相关资源
              最近更新 更多