MSSQL:一种可重复使用的查询表中所有数据子集的方法

时间:2019-04-08 10:11:25

标签: sql-server

假设一个系统,其中People可以访问Buildings,而在建筑物中,则可以访问某些Rooms。 访问权限是根据关联的Permissions表定义的;对于具有完全访问权限的人员,则是完全访问权限。

db表的定义如下:

buildings (id INT)
rooms (id INT, building_id INT)
people (id INT, has_full_access BIT)
building_permissions (building_id INT, person_id INT)
room_permissions (room_id INT, person_id INT)

当前,我具有表值函数,这些函数会根据人员的ID以及他们是否具有完全访问权限来返回带有建筑物和房间的授权ID的表。

CREATE FUNCTION fn_get_authorised_buildings (@person_id INT, @has_full_access BIT)
RETURNS TABLE AS
RETURN
(
    SELECT b.id
    FROM buildings b
    WHERE @has_full_access = 1

    UNION

    SELECT b.id
    FROM buildings b
        INNER JOIN building_permissions bp ON bp.building_id = b.id
    WHERE bp.person_id = @person_id 
);

CREATE FUNCTION fn_get_authorised_rooms (@person_id INT, @has_full_access BIT)
RETURNS TABLE AS
RETURN
(
    SELECT r.id
    FROM rooms r
    WHERE @has_full_access = 1

    UNION

    SELECT r.id
    FROM rooms r
        INNER JOIN room_permissions rp ON rp.room_id = r.id
    WHERE rp.person_id = @person_id 
);

每当涉及建筑物和房间时,我需要遍历整个系统,我需要根据人员的权限过滤这些表。如果该人具有完全访问权限,则必须包括所有行,否则仅包括他们有权访问的行。

我的查询(简体)看起来像这样:

DECLARE @person_id INT = 123
DECLARE @has_full_access BIT = 1

DECLARE @authorised_buildings TABLE (id INT) 
INSERT INTO @authorised_buildings SELECT id FROM fn_get_authorised_buildings(@person_id , @has_full_access)

DECLARE @authorised_rooms TABLE (id INT) 
INSERT INTO @authorised_rooms SELECT id FROM fn_get_authorised_rooms(@person_id, @has_full_access)

--Example A
SELECT * 
FROM buildings b
    INNER JOIN rooms r ON r.building_id = b.id
WHERE 1 = 1
    AND b.id IN (SELECT id FROM @authorised_buildings)
    AND r.id IN (SELECT id FROM @authorised_rooms)

--Example B
SELECT * 
FROM floors f -- or other tables that are related to rooms
    INNER JOIN rooms r ON r.floor_id = f.id
WHERE 1 = 1
    AND r.id IN (SELECT id FROM @authorised_rooms)

有更好的方法吗?

编辑: Here摆弄了摆设

1 个答案:

答案 0 :(得分:0)

您可以创建一个包含所有逻辑的视图,

CREATE VIEW bulding_rooms_per_person AS
SELECT p.id AS person_id, b.id as building_id, r.id AS room_id
FROM people p 
LEFT JOIN building_permissions bp ON bp.person_id = p.id
LEFT JOIN room_permissions rp ON rp.person_id = p.id
INNER JOIN buildings b ON b.id = bp.building_id OR p.has_full_access = 1
INNER JOIN rooms r ON r.building_id = b.id AND (r.id = rp.room_id OR p.has_full_access = 1)

然后对其进行查询:

SELECT * from bulding_rooms_per_person WHERE person_id = @person_id