替代动态SQL的函数

时间:2012-02-24 11:41:13

标签: sql-server sql-server-2008 stored-procedures

我有一个存储过程,目前返回一个projectID列表。我想扩展它以返回一些额外的信息,以确定特定用户是否有权访问该项目。

要确定用户是否具有访问权限,我需要在名为“Project_XXX”的表中查找用户,其中XXX是projectID。是的,这是令人震惊的数据库设计,但遗憾的是我无能为力。我的第一直觉是我可以使用这样的函数:

SELECT ProjectID WHERE [criteria] AND myfunc(ProjectID, @username)=1

但是,因为查找需要运行动态SQL,所以它告诉我我不能这样做。

这让我可以选择将逻辑放在存储过程中,但是我的select的语法并不简单。

我能想到的方法是运行select来获取projectID列表,然后在该表上运行一个光标调用我的存储过程,但我不再考虑那里,因为它看起来太复杂了...... / p>

那么有什么方法可以用上面类似的简单语法做我想做的事情吗?有没有办法让用户函数基于动态SQL返回?有没有像我上面那样使用存储过程的好方法?我确定我遗漏了一些明显的东西 - 我很少需要做任何复杂的SQL。 ; - )

我还应该重申,我知道基础问题与愚蠢的单个项目表有关,但这不是可以改变的。

2 个答案:

答案 0 :(得分:2)

一种选择是从所有project_xxx表创建一个视图。类似的东西:

CREATE VIEW SecurityTable
AS
SELECT 'Project_1', User, HasAccess
FROM   Project_1
UNION
SELECT 'Project_2', User, HasAccess
FROM   Project_2
UNION
SELECT 'Project_3', User, HasAccess
FROM   Project_3
etc...

然后您可以简单地查询您的视图,就像数据库的设计正确一样; - )

SELECT ProjectID, User
FROM   SecurityTable
WHERE [criteria]
AND   HasAccess=1

<小时/> 正如您所说,您将经常添加新的项目表,我建议您每天早上都可以使用动态查询填充安全表。例如:

CREATE TABLE Project_1 (
    Usr varchar(20),
    HasAccess bit)
GO
CREATE TABLE Project_2 (
    Usr varchar(20),
    HasAccess bit)
GO
CREATE TABLE SecurityTable (
    Usr varchar(20),
    HasAccess bit)
GO


INSERT INTO Project_1 (Usr, HasAccess) VALUES ('Kermit', 1)
INSERT INTO Project_1 (Usr, HasAccess) VALUES ('MissPiggy', 1)
INSERT INTO Project_2 (Usr, HasAccess) VALUES ('Beaker', 1)
INSERT INTO Project_2 (Usr, HasAccess) VALUES ('TheCount', 0)
GO

Create Procedure LoadSecurityTable 
AS
    DELETE * FROM SecurityTable

    EXEC sp_MSForEachTable 
        @command1 = 'INSERT INTO SecurityTable (Usr, HasAccess) SELECT Usr, HasAccess FROM ?',
        @whereand = 'AND o.name LIKE ''Project_%'''
GO

EXEC LoadSecurityTable
SELECT * FROM SecurityTable

答案 1 :(得分:1)

如您所知,您无法在函数中运行动态SQL或调用存储过程。

有一个非常丑陋的解决方法,涉及使用xp_cmdshell从函数中调用批处理脚本(.bat),并在批处理脚本中使用sp_executesql来执行动态SQL。

但是,为了简单起见,我会使用RB的视图解决方案!