문제

액세스 제어 시스템을 만들려고합니다.

다음은 내가 룩에 대한 액세스를 제어하려는 테이블의 예를 살펴 봅니다.

things table:
id   group_id   name
1    1          thing 1
2    1          thing 2
3    1          thing 3
4    1          thing 4
5    2          thing 5

그리고 액세스 제어 테이블은 다음과 같습니다.

access table:
user_id  type   object_id  access
1        group  1          50
1        thing  1          10
1        thing  2          100

'사물'의 ID를 직접 지정하여 액세스를 부여하거나 그룹 ID를 지정하여 전체 그룹에 대해 부여 할 수 있습니다. 위의 예에서, 사용자 1은 50에서 그룹 1에서 액세스 레벨을 부여 받았으며, 이는 개인에 대한보다 구체적인 액세스 권한을 부여하는 다른 규칙이없는 한 적용되어야합니다.

특정 사용자의 액세스 레벨과 함께 사물 목록 (ID 만 괜찮습니다)을 반환하는 쿼리가 필요합니다. 위의 예를 사용하여 사용자 ID 1에 대해 이와 같은 것을 원합니다.

desired result:
thing_id   access
1          10
2          100
3          50   (things 3 and 4 have no specific access rule,
4          50   so this '50' is from the group rule)
5               (thing 5 has no rules at all, so although I 
                still want it in the output, there's no access
        level for it)

내가 생각해 낼 수있는 가장 가까운 것은 다음과 같습니다.

SELECT * 
FROM things 
LEFT JOIN access ON 
    user_id = 1
    AND (
        (access.type = 'group' AND access.object_id = things.group_id)
        OR (access.type = 'thing' AND access.object_id = things.id)
    )

그러나 그것은 '사물'테이블의 각 행에만 하나만 원할 때 여러 행을 반환합니다. 각 '사물'에 대해 단일 행으로 내려가는 방법이나 '그룹'규칙을 우선시하는 방법을 잘 모르겠습니다.

도움이되면 사용중인 데이터베이스는 PostgreSQL입니다.

내가 놓친 정보가 있으면 의견을 남겨 주시기 바랍니다.

미리 감사드립니다!

도움이 되었습니까?

해결책

Postgres SQL 방언을 모르지만 다음과 같은 것일 수 있습니다.

select thing.*, coalesce ( ( select access
                             from   access
                             where  userid = 1
                             and    type = 'thing'
                             and    object_id = thing.id
                           ),
                           ( select access
                             from   access
                             where  userid = 1
                             and    type = 'group'
                             and    object_id = thing.group_id
                           )
                         )
from things

덧붙여서, 나는 디자인을 좋아하지 않는다. 액세스 테이블을 두 가지로 나누는 것을 선호합니다.

thing_access (user_id, thing_id, access)
group_access (user_id, group_id, access)

그런 다음 내 쿼리가됩니다.

select thing.*, coalesce ( ( select access
                             from   thing_access
                             where  userid = 1
                             and    thing_id = thing.id
                           ),
                           ( select access
                             from   group_access
                             where  userid = 1
                             and    group_id = thing.group_id
                           )
                         )
from things

외국 키는 이제 액세스 테이블에서 사용할 수 있기 때문에 이것을 선호합니다.

다른 팁

나는 어제 밤에 종이를 읽었습니다. 이 작업을 수행하는 방법에 대한 아이디어가 있습니다. 제목에서 링크를 사용할 수없는 경우 Google Scholar를 사용해보십시오. 해마 데이터베이스의 공개 제한.

몇 가지 좋은 답변이 있지만 가장 효율적인 것은 아마도 다음과 같은 것일 것입니다.

SELECT things.id, things.group_id, things.name, max(access) 
FROM things 
LEFT JOIN access ON 
        user_id = 1 
        AND (
                (access.type = 'group' AND access.object_id = things.group_id)
                OR (access.type = 'thing' AND access.object_id = things.id)
        )
group by things.id, things.group_id, things.name

이것은 단순히 당신이 찾고있는 것을 얻기 위해 쿼리에 추가 된 요약을 사용합니다.

토니 :

나쁜 해결책이 아니라, 나는 그것을 좋아하는 것 같습니다. 사소한 조정 후 쿼리는 다음과 같습니다.

SELECT 
    things.*, 
    coalesce ( 
        (   SELECT access 
            FROM access 
            WHERE user_id = 1 
                AND type = 'thing' 
                AND object_id = things.id
        ), 
        (   SELECT access 
            FROM access 
            WHERE user_id = 1 
                AND type = 'group' 
                AND object_id = things.group_id 
        ) 
    ) AS access
    FROM things;

그리고 결과는 정확해 보입니다.

 id | group_id |  name   | access 
----+----------+---------+--------
  1 |        1 | thing 1 |     10
  2 |        1 | thing 2 |    100
  3 |        1 | thing 3 |     50
  4 |        1 | thing 4 |     50
  5 |        2 | thing 5 |       

그래요 완전히 이상적인 스키마가 아닌 것에 대해 지적하십시오. 그러나 나는 어느 정도 그것에 붙어 있습니다.


Josef :

당신의 해결책은 내가 가지고있는 것들과 매우 유사하며, 내 본능 (예 : 그것들과 같은)은 그렇게 할 수 있다고 말해줍니다. 불행히도 완전히 올바른 결과를 얻지 못합니다.

 id | group_id |  name   | max 
----+----------+---------+-----
  1 |        1 | thing 1 |  50
  2 |        1 | thing 2 | 100
  3 |        1 | thing 3 |  50
  4 |        1 | thing 4 |  50
  5 |        2 | thing 5 |    

'Thing 1'의 액세스 레벨은 10의보다 구체적인 'Thing'액세스 값보다는 더 높은 '그룹'액세스 값을 가져 왔습니다. 나는 그것을 고치는 방법이 있다고 생각하지 않습니다. GROUP BY, 그러나 누군가 제안이 있다면 그 시점에서 부정확 한 것으로 입증되어 기쁩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top