كيف يمكنني أن أفعل الوصول التحكم عن طريق جدول SQL؟

StackOverflow https://stackoverflow.com/questions/200810

  •  03-07-2019
  •  | 
  •  

سؤال

وأنا أحاول أن إنشاء نظام لمراقبة الدخول.

وهنا جردت أسفل مثال على ما الجدول أحاول التحكم في الوصول إلى يشبه:

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

ويمكن الحصول على منح إما عن طريق تحديد هوية من 'شيء' مباشرة، أو منح لمجموعة كاملة من الاشياء عن طريق تحديد هوية المجموعة. في المثال أعلاه، تم منح المستخدم 1 مستوى الوصول من 50 الى مجموعة 1، التي يجب أن تطبق ما لم تكن هناك أي قواعد أخرى منح وصول أكثر تحديدا إلى شيء الفردية.

وأحتاج استعلام يقوم بإرجاع قائمة من الأشياء (هويات ما يرام فقط) جنبا إلى جنب مع مستوى الوصول لمستخدم معين. وذلك باستخدام المثال أعلاه كنت أريد شيئا من هذا القبيل للمستخدم معرف 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)
    )

ولكن هذا يعود صفوف متعددة، عندما أريد واحدة فقط لكل صف في الجدول "الأشياء". أنا لست متأكدا من كيفية ننكب على صف واحد لكل "شيء"، أو كيفية تحديد الأولويات "شيء" قواعد على قواعد "مجموعة".

وإذا كان يساعد، وقاعدة بيانات أنا باستخدام هي كيو.

لا تتردد في ترك التعليق إذا كان هناك أي معلومات لقد غاب.

ويرجع الفضل في ذلك مسبقا!

هل كانت مفيدة؟

المحلول

وأنا لا أعرف لهجة بوستجرس 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 على rel="nofollow الحد الإفصاح في أبقراط قواعد البيانات.

وفي حين أن هناك عدة أجوبة جيدة، فإن الأكثر كفاءة ربما يكون شيئا مثل هذا:

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 |       

وأفعل <م> تماما اتخاذ نقطة عن أنه لم يكن مخطط مثالي. ومع ذلك، وأنا عالقة معها إلى حد ما.


وجوزيف:

والحل الخاص بك هو تشبه الى حد بعيد الاشياء كنت ألعب معها، وبلدي الغرائز (مثل هم) يقول لي أنه ينبغي أن يكون من الممكن أن تفعل ذلك بهذه الطريقة. لسوء الحظ أنها لا تنتج النتائج الصحيحة تماما:

 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 |    

لقد اتخذت مستوى الوصول ل"الشيء 1" القيمة وصول "مجموعة" أعلى، بدلا من "شيء" القيمة وصول أكثر تحديدا من 10، وهو ما أنا بعد. أنا لا أعتقد أن هناك وسيلة لتحديد ذلك ضمن GROUP BY، ولكن إذا كان أي شخص لديه أي اقتراحات أنا أكثر من سعيدة لإثبات غير صحيحة حول هذه النقطة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top