2016-08-31 6 views
2

私は問題があります。どのように私はパーミッションを実装するべきですか?それは常に追加/変更できますか?どのような種類のフラグ/許可の実装が必要ですか?

今、私はこの持っている:私のデータベーステーブル方式はフィールドflags

  • を持って

    • を私は経由で必要なものを選択することができ、例えば、SELECT * from some_table WHERE flags&'.FLAG_CLOSED|FLAG_ACTIVE.'='.FLAG_CLOSED|FLAG_ACTIVE;
    • すべてのフラグは、コード
    内部定数であります

    サンプルコード、ちょうど私が意味するものを理解するためのものです(実際のコードではなく、テストされていません):

    class Sample { 
    
        const FLAG_ACTIVE = 0x01; 
        const FLAG_CLOSED = 0x02; 
        const FLAG_DELETED = 0x04; 
    
        private $db; 
    
        public function __construct(...) { 
         /* ... */ 
        } 
    
        public function getClosed() { 
         $flags = self::FLAG_ACTIVE | self::FLAG_CLOSED; 
         $query = 'SELECT * FROM `test` WHERE `flags`&'.$flags.'='.$flags; 
         $stmt = $this->db->query($query); 
         return $stmt->fetch(\PDO::FETCH_ASSOC); 
        } 
    } 
    

    フィルタリングされた結果を1つのフィールド比較で簡単に取得できますが、コード内で変更するのは面倒です。

    もう1つの方法は、フラグと値を持つ必要がある追加のテーブルを作成することです。しかし、より効率的なものは何でしょうか?値にビットフィールドベースの値(1,2,8,8など)があるか、 'CLOSED'、 'ACTIVE'などの値が必要ですか?

    この2例では、テーブルの行の意志は次のようになります。私は `WHERE「%CLOSED%」のようなフラグと「%ACTIVE%」のようなフラグでフィルタリングする必要がある後者の場合には

    id, description, flags 
    =============== 
    1, 'test', 0x12 
    1, 'test', 'CLOSED,ACTIVE' 
    

    ああ..ここにフラグを実装する別の方法があります。 IdFlagのテーブルを作成する。 Like:

    Id, flag 
    ======== 
    1, CLOSED 
    1, ACTIVE 
    

    ここにはより効率的な実装がありますか?

    P.S.ご不便をお祈り申し上げます。まずは質問です。

    p.p.s.私はちょうどこのスキームを繰り返す必要はありません、私はちょうどより効率的な方法でそれを行うアドバイスを要求した、それはビットフィールドの値なしで絶対に簡単な実装することができます。

  • +2

    本当にこれを行うには、 'SET'データ型を見てください。しかし、このようなビットフィールドは索引付けできないため、フラグをビットとして組み合わせるのではなく、別々の行にテーブルを作成することをお勧めします。 – Barmar

    +0

    @Barmar、アドバイスをいただきありがとうございます。私は必要ですが、新しいフラグを使ってSETを拡張することはできますか?たとえば、テーブルに700kレコードがあるとします。そして、データベースからすべてのSET値を取り出すことはできますか?キャッシュを使用することはできますが、効率はどうですか? – Wizard

    +0

    'SET'の要素の順序を変更しない限り、問題なく拡張できます。 'SET'は内部的にビットフィールドとして実装されています。 – Barmar

    答えて

    2

    このために単一のフラグフィールドを使用しないで、フラグごとに別々の行を持つテーブルを使用します。

    CREATE TABLE flags (
        thing_id INT, 
        flag VARCHAR(32), 
        PRIMARY KEY (thing_id, flag), 
        FOREIGN KEY (thing_id) REFERENCES things (id), 
        INDEX (flag) 
    ); 
    

    行は次のようになります。そして、特定のフラグを持つすべてのものを見つけるために

    thing_id flag 
    1  active 
    1  closed 
    2  closed 
    3  deleted 
    3  active 
    

    、あなたがテーブルに参加:

    SELECT t.* 
    FROM things AS t 
    JOIN flags as f ON f.thing_id = t.id 
    WHERE f.flag = 'closed'; 
    

    は事のフラグのすべてを取得するには、使用GROUP_CONCAT

    SELECT t.*, GROUP_CONCAT(f.flag) AS flags 
    FROM things AS t 
    JOIN flags as f ON f.thing_id = t.id 
    WHERE t.id = :thing_id 
    

    存在しないはずのフラグを作成しないようにする場合は、flagカラムをflag_namesテーブルに外部キーにすることができます。

    +0

    答えをありがとう。それは私が聞く必要があるすべて(そしてさらに)です。非常に感謝します。 – Wizard

    +0

    提案として - 値がint(1,2,4 ... 32)になる場合、いくつかの制限を使って改善することができます。そして、我々は 'concat'を使わずに' sum'を使って全てのフラグを得ることができます。制限 - bigintのサポートなしに、「もの」ごとに32/64以上のフラグを持つことはできません。ほとんどの場合、それで十分です。 – Wizard

    +0

    実際、私たちの会社は数値の 'flags'カラムを持つテーブルを持っていて、オーバーフローしたときにこのメソッドに切り替えました。数値フラグを使用するように記述されたすべてのアプリケーションのために、変換するストアド関数を追加しました。 – Barmar

    関連する問題