19

テーブルにビット単位のフラグを含むフィールドがあります。例として、3つのフラグがあるとしましょう。4 => read, 2 => write, 1 => executeテーブルは次のようになります*

  user_id  |  file  |  permissions
-----------+--------+---------------
        1  |  a.txt |  6    ( <-- 6 = 4 + 2 = read + write)
        1  |  b.txt |  4    ( <-- 4 = 4 = read)
        2  |  a.txt |  4
        2  |  c.exe |  1    ( <-- 1 = execute)

任意のレコードに特定のフラグが設定されている(例:書き込み)すべてのユーザーを見つけることに興味があります。1つのクエリでこれを行うために、すべてのユーザーのアクセス許可をORすると、ユーザーのアクセス許可の「合計」である単一の値が得られると考えました。

  user_id  |  all_perms
-----------+-------------
        1  |  6        (<-- 6 | 4 = 6)
        2  |  5        (<-- 4 | 1 = 5)

*私の実際のテーブルは、ファイルやファイルのパーミッションとは関係ありません。

これを1つのステートメントで実行する方法はありますか?私の見方では、GROUPBYを使用した通常の集計関数と非常によく似ています。

SELECT user_id, SUM(permissions) as all_perms
FROM permissions
GROUP BY user_id

...しかし、明らかに、SUMの代わりにいくつかの魔法の「ビット単位」関数があります。誰かそのようなことを知っていますか?

(ボーナスポイントについては、オラクルで機能しますか?)

4

5 に答える 5

21

MySQL:

SELECT user_id, BIT_OR(permissions) as all_perms
FROM permissions
GROUP BY user_id
于 2009-09-09T07:12:38.427 に答える
8

ああ、質問の5分後に答えが見つかった別の質問...受け入れられた答えはMySQLの実装に送られます...

Radinoのブログで発見したように、Oracleでそれを行う方法は次のとおりです。

オブジェクトを作成します...

CREATE OR REPLACE TYPE bitor_impl AS OBJECT
(
  bitor NUMBER,

  STATIC FUNCTION ODCIAggregateInitialize(ctx IN OUT bitor_impl) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateIterate(SELF  IN OUT bitor_impl,
                                       VALUE IN NUMBER) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateMerge(SELF IN OUT bitor_impl,
                                     ctx2 IN bitor_impl) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateTerminate(SELF        IN OUT bitor_impl,
                                         returnvalue OUT NUMBER,
                                         flags       IN NUMBER) RETURN NUMBER
)
/

CREATE OR REPLACE TYPE BODY bitor_impl IS
  STATIC FUNCTION ODCIAggregateInitialize(ctx IN OUT bitor_impl) RETURN NUMBER IS
  BEGIN
    ctx := bitor_impl(0);
    RETURN ODCIConst.Success;
  END ODCIAggregateInitialize;

  MEMBER FUNCTION ODCIAggregateIterate(SELF  IN OUT bitor_impl,
                                       VALUE IN NUMBER) RETURN NUMBER IS
  BEGIN
    SELF.bitor := SELF.bitor + VALUE - bitand(SELF.bitor, VALUE);
    RETURN ODCIConst.Success;
  END ODCIAggregateIterate;

  MEMBER FUNCTION ODCIAggregateMerge(SELF IN OUT bitor_impl,
                                     ctx2 IN bitor_impl) RETURN NUMBER IS
  BEGIN
    SELF.bitor := SELF.bitor + ctx2.bitor - bitand(SELF.bitor, ctx2.bitor);
    RETURN ODCIConst.Success;
  END ODCIAggregateMerge;

  MEMBER FUNCTION ODCIAggregateTerminate(SELF        IN OUT bitor_impl,
                                         returnvalue OUT NUMBER,
                                         flags       IN NUMBER) RETURN NUMBER IS
  BEGIN
    returnvalue := SELF.bitor;
    RETURN ODCIConst.Success;
  END ODCIAggregateTerminate;
END;
/

...次に、独自の集計関数を定義します

CREATE OR REPLACE FUNCTION bitoragg(x IN NUMBER) RETURN NUMBER
PARALLEL_ENABLE
AGGREGATE USING bitor_impl;
/

使用法:

SELECT user_id, bitoragg(permissions) FROM perms GROUP BY user_id
于 2009-09-09T06:57:52.937 に答える
2

そして、あなたはビットごとにまたはで行うことができます...

FUNCTION BITOR(x IN NUMBER, y IN NUMBER)
RETURN NUMBER
AS
BEGIN
    RETURN x + y - BITAND(x,y);
END;
于 2009-09-09T06:59:13.573 に答える
1

可能性のあるパーミッション コンポーネント (1、2、および 4) をアプリオリに知る必要がありますが (したがって、維持するのが難しくなります)、これは非常に単純で機能します。

SELECT user_id,
       MAX(BITAND(permissions, 1)) +
       MAX(BITAND(permissions, 2)) +
       MAX(BITAND(permissions, 4)) all_perms
FROM permissions
GROUP BY user_id
于 2013-01-02T03:23:32.923 に答える
0

任意のレコードに特定のフラグが設定されている(例:書き込み)すべてのユーザーを見つけることに興味があります

単に何が問題なのですか

SELECT DISTINCT User_ID
FROM Permissions
WHERE permissions & 2 = 2
于 2009-09-09T07:10:28.510 に答える