SQL:如果存在,则限制用户。如果不存在则显示一切

时间:2017-07-07 14:57:30

标签: sql-server tsql exists

我试图找到满足这一要求的最佳方法:

@fkStaffID INT =当前用户。

如果@fkStaffID获得资源BLABLA只显示表X的行,其中StaffID就在这里。如果他没有资源BLABLA,那就显示一切。

对于雇主的安全政策,我无法粘贴完整的SQL。 (我希望我能够提供足够的帮助,而不是太多安全......)

我的所作所为:

SELECT * FROM X
WHERE ((EXISTS
(SELECT 1 FROM STAFF WHERE pkStaff=@fkStaffID
AND STAFF.PkStaff IN (SELECT fkStaff FROM SECURITYSUBQUERY WHERE ResourceName='BLABLA')) AND X.fkStaff=@fkStaffID)
OR ((NOT EXISTS (SELECT 1 FROM STAFF WHERE pkStaff=@fkStaffID
AND STAFF.PkStaff IN (SELECT fkStaff FROM SECURITYSUBQUERY WHERE ResourceName='BLABLA')) )

问题:它真的很慢。我可以做一个更有效的方式吗?我可以换一种方式吗?谢谢你的帮助!

3 个答案:

答案 0 :(得分:1)

我认为您应该能够对查询进行qrite:

SELECT * FROM x
WHERE @fkStaffID NOT IN (SELECT fkStaff FROM SecuritySubquery WHERE ResourceName= 'BLABLA')
   OR @fkStaffID = fkStaff;

因此,@fkStaffID不是'BLABLA',或者它与记录的员工ID相匹配。

NOT IN / OR仍然非常快。无论如何,你应该有以下索引:

CREATE INDEX idx1 ON SecuritySubquery (ResourceName, fkStaff);
CREATE INDEX idx2 ON x (fkStaff);

答案 1 :(得分:0)

我会试试这个:

if exists(select 1 from staff where pkstaff=@fkstaffid)
    begin
        select * from X where ResourceName = 'Blabla' and fkStaff = @fkStaffId
    end
else
    begin
        select * from X where ResourceName = 'Blabla'
    end

如果我们有匹配的记录,那么我们会按@fkStaffId进行过滤,否则我们会选择所有内容。

答案 2 :(得分:0)

以下查询将仅为您提供X个人的数据,这些人在STAFF表中,在SECURITYSUBQUERY表中有相应的记录(' BlaBla'记录)。

首先,构建测试数据。

IF OBJECT_ID(N'tempdb..#x') IS NOT NULL
     DROP TABLE #x

CREATE TABLE #X ( fkStaff int, myStuff varchar(20) )
INSERT INTO #X ( fkStaff, myStuff )
VALUES 
      (1,'not me')
    , (2,'not me')
    , (3,'show me')
    , (4,'not me')
    , (5,'show me too')

IF OBJECT_ID(N'tempdb..#STAFF') IS NOT NULL
     DROP TABLE #STAFF

CREATE TABLE #STAFF ( pkStaff int, name varchar(20) )
INSERT INTO #STAFF ( pkStaff, name )
VALUES 
      (1, 'Joe')
    , (2, 'Jim')
    , (3, 'Bill')
    , (4, 'Ted')
    , (5, 'Rufus')

IF OBJECT_ID(N'tempdb..#SECURITYSUBQUERY') IS NOT NULL
     DROP TABLE #SECURITYSUBQUERY

CREATE TABLE #SECURITYSUBQUERY ( fkStaff int, ResourceName varchar(20) )
INSERT INTO #SECURITYSUBQUERY ( fkStaff, ResourceName )
VALUES 
      ( 1, 'NotAuth' )
    , ( 2, 'NotAuth' )
    , ( 3, 'BlaBla' )
    , ( 3, 'Extra Perm' )
    , ( 4, 'NotAuth' )
    , ( 5, 'BlaBla' )

现在进行查询。

DECLARE @fkStaffID int ; /* Only 3 or 5 will return records. */

SELECT x.* 
FROM #x x 
LEFT OUTER JOIN (
    SELECT s.pkStaff
    FROM #STAFF s
    INNER JOIN #SECURITYSUBQUERY ss ON s.pkStaff = ss.fkStaff
        AND ss.ResourceName = 'BlaBla'
    WHERE s.pkStaff = @fkStaffID
) t ON t.pkStaff = x.fkStaff
WHERE t.pkStaff IS NOT NULL
    AND x.fkStaff = @fkStaffID

如果用户Bill或Rufus已登录(并作为@fkStaffID传递),这将仅显示结果。

我不知道这会扩展得多好,但优化器应该比EXISTS或NOT IN子查询工作得更快。尝试使用您的数据。