我可以在存储过程中设置默认架构吗?

时间:2009-10-15 00:24:27

标签: sql-server sql-server-2005 stored-procedures schema

我正在进行StackQL的下一次更新。

我想做的一件事是能够查询多个版本。因此,当我加载十月数据时,我没有删除旧的九月数据库。它还在那里。实际上,您甚至可以通过包含如下数据库名称来查询它:

select top 10 * from SO_Sept09..Posts

当他们开始为ServerFault和SuperUser提供数据时,这将更加重要。

但我不喜欢拥有一大堆数据库来支持这一点。我宁愿将所有数据放在同一个数据库中,并将每个不同的集合分成它自己的模式。但为了使这成为可能,我需要能够根据传递给存储过程的参数设置默认模式作为运行查询的存储过程的一部分,该参数告诉用户从未来的下拉列表中选择哪个数据库出现在工具栏中。

StackQL的查询最终只是传递给exec()函数,如下所示:

exec(@QueryText)

我可以在存储过程中做任何事情,或者在QueryText字符串(ala USE [DatabaseName])前面设置查询中使用的默认架构吗?

5 个答案:

答案 0 :(得分:13)

这里有各种各样的地方,但不完全是这样。这样做的方法是:

  1. 进行独特的登录&每个架构的用户

  2. 让这些用户成为每个不同架构的所有者。

  3. 将每个此类用户的默认架构设置为他们拥有的架构。

  4. 使用语法EXECUTE ('sql commands') AS USER = 'schema-owner'在该默认架构的上下文中执行SQL命令。

  5. 以下脚本演示了这一点:

    --====== Create the Login for the User:
    CREATE LOGIN [UserTest1] WITH PASSWORD='whatever', DEFAULT_DATABASE=[TestUsers], DEFAULT_LANGUAGE=[us_english]
    GO
    
    --====== Make a User for the Login:
    CREATE USER [UserTest1] FOR LOGIN [UserTest1]
    GO
    
    --====== Make a Schema owned by the User and default to it:
    --        (I assume that you already have the schemas)
    CREATE SCHEMA [UserTest1] AUTHORIZATION [UserTest1]
    GO
    ALTER USER [UserTest1] WITH DEFAULT_SCHEMA=[UserTest1]
    GO
    
    --====== Make a sProc in dbo
    CREATE PROCEDURE [dbo].[TestSchema_Exec] AS
        SELECT 'executing in schema [dbo]'
    GO
    --====== Make a similar sProc in New Schema
    CREATE PROCEDURE [UserTest1].[TestSchema_Exec] AS
        SELECT 'executing in schema [UserTest1]'
    GO
    
    --========= Demonstrate that we can switch Default Schemas:
    EXEC('TestSchema_Exec')
    
    EXEC('TestSchema_Exec') AS USER = 'UserTest1'
    

答案 1 :(得分:3)

除了修改@QueryText本身之外,我唯一能想到的是用户的默认架构:

ALTER USER SO_Sept09_Reader WITH DEFAULT_SCHEMA = SO_Sept09

...然后以您想要使用的每个架构的不同用户身份进行连接。 Hackity hack。

但是如果您的查询是动态构造的(并且我确定您知道为什么这通常不是一个好主意),最简单的方法是将一个架构占位符添加到查询文本中,并传递架构名称和对替换函数的查询。

答案 2 :(得分:1)

另一种可能性是在每个模式中生成每个SP的副本,SP中未修改的表名称指的是同一模式中的表。

请注意,这不适用于此类SP中的动态SQL:

CREATE PROCEDURE schema_a.SP
    @somesql AS varchar(MAX)
AS
BEGIN
    EXEC ( @somesql )
END

CREATE PROCEDURE schema_b.SP
    @somesql AS varchar(MAX)
AS
BEGIN
    EXEC ( @somesql )
END

无效,因为EXEC中的架构亲和力会丢失。

虽然这个:

CREATE PROCEDURE schema_a.SP
AS
BEGIN
    SELECT * FROM tbl -- Will use schema_a.tbl first
END

CREATE PROCEDURE schema_b.SP
AS
BEGIN
    SELECT * FROM tbl -- Will use schema_b.tbl first
END

工作正常。

类似地:

EXEC ( 'EXEC schema_a.SP' )

显然会正常工作。

答案 3 :(得分:0)

未尝试,但是:您可以将不同的模式数据合并到一个视图中,并添加一个调用模式名称的列吗?

CREATE VIEW AllPosts AS
  SELECT Data1, Data2, 'Sept09' AS Partition FROM SO_Sept09..Posts
    UNION ALL
  SELECT Data1, Data2, 'Oct09' AS Partition FROM SO_Oct09..Posts
  ...

SELECT * FROM AllPosts WHERE Partition = 'Sept09'
SELECT * FROM dbo.AllPosts('Sept09') -- if use table-valued function instead

答案 4 :(得分:0)

好的,我有一种新方法可以帮助我做得更好。这是我对Michael Petrotta的回答的一个变体:

  

但它确实让我想到可能有几个用户并在运行中选择连接字符串。

我要做的是只有一个用户来执行这些查询,但我会动态更换连接字符串以指定正确的初始目录。