Frage

Ich versuche, ein Zutrittskontrollsystem zu schaffen.

Hier ist ein abgespeckte Beispiel dafür, was die Tabelle Ich versuche, wie Zugang zu Aussehen zu steuern:

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

Und die Zugriffssteuerungstabelle sieht wie folgt aus:

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

Der Zugang kann gewährt werden, indem entweder die ID des ‚Dings‘ spezifiziert direkt oder für eine ganze Gruppe von Dingen, gewährt durch eine Gruppe-ID angeben. In dem obigen Beispiel Benutzer 1 wurde eine Zugriffsstufe von 50 bis Gruppe 1 gewährt, es sei denn es andere Regeln gelten sollten präziser Zugriff auf eine einzelne Sache zu gewähren.

Ich brauche eine Abfrage, die eine Liste der Dinge gibt (ids nur in Ordnung ist) zusammen mit der Zugriffsebene für einen bestimmten Benutzer. So am Beispiel oben ich so etwas wie dies für Benutzer-ID 1 wollen würde:

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)

Die nächstgelegene ich mit oben kommen kann, ist dies:

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)
    )

Aber das gibt mehrere Zeilen, wenn ich für jede Zeile nur eine will in der Tabelle ‚Dinge‘. Ich bin mir nicht sicher, wie für jedes ‚Ding‘, auf eine einzige Zeile zu erhalten oder, wie zu priorisieren ‚Ding‘ Regeln über ‚Gruppe‘ Regeln.

Wenn es hilft, die Datenbank ich benutze ist PostgreSQL.

Bitte fühlen Sie sich frei um einen Kommentar zu hinterlassen, wenn es irgendwelche Informationen, das ich verpasst habe aus.

Vielen Dank im Voraus!

War es hilfreich?

Lösung

Ich weiß nicht, den Postgres SQL-Dialekt, aber vielleicht so etwas wie:

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

Übrigens, ich mag nicht das Design. Ich würde die Zugriffstabelle lieber in zwei werden:

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

Meine Abfrage wird dann:

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

Ich ziehe dies, weil Fremdschlüssel kann nun in den Access-Tabellen verwendet werden.

Andere Tipps

Ich habe gerade gelesen ein Papier gestern Abend zu diesem Thema. Es hat einige Ideen, wie dies zu tun. Wenn Sie nicht auf den Link auf den Titel verwenden können, versuchen Sie es mit Google Scholar auf Disclosure Begrenzung in hippokratischen Datenbanken.

Zwar gibt es mehrere gute Antworten sind, die effizienteste wahrscheinlich so etwas wie dieses wäre:

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

Welche verwendet einfach Verdichtungs hinzugefügt, um Sie abfragen, um zu bekommen, was Sie suchen.

Tony:

Keine schlechte Lösung, ich mag es, scheint zu funktionieren. Hier ist Ihre Abfrage nach kleinerem Tweaking:

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;

Und die Ergebnisse sehen richtig:

 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 |       

ich vollständig nehmen Sie den Punkt, um es kein ideales Schema zu sein. Allerdings bin ich mit ihm zu einem gewissen Grad fest.


Josef:

Ihre Lösung ist sehr ähnlich wie die Sachen, die ich mit spiele, und meine Instinkte (wie sie sind) sagt mir, dass es möglich sein sollte, es so zu tun. Leider produziert es nicht ganz korrekt Ergebnisse:

 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 |    

Die Zugriffsebene für ‚Ding 1‘ hat die höhere ‚Gruppe‘ Zugriffswert genommen, anstatt die speziellere ‚Ding‘ Zugriffswert von 10, das ist das, was ich bin nach. Ich glaube nicht, gibt es eine Möglichkeit, dass innerhalb eines GROUP BY zu beheben, aber wenn jemand irgendwelche Vorschläge ich mehr als glücklich bin zu in diesem Punkt falsch nachgewiesen werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top