¿Es posible realizar una function de grupo bit a bit?

Tengo un campo en una tabla que contiene banderas bit a bit. Digamos por el bien del ejemplo, hay tres indicadores: 4 => read, 2 => write, 1 => execute y la tabla se ve así * :

  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) 

Estoy interesado en encontrar todos los usuarios que tienen un determinado set de banderas (por ejemplo, escribir) en CUALQUIER logging. Para hacer esto en una consulta, calculé que si orderaba TODOS los permissions del usuario juntos obtendría un valor único que es la "sum total" de sus permissions:

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

* Mi tabla real no tiene que ver con files o permissions de files, 'es solo un ejemplo

¿Hay alguna manera de que pueda realizar esto en una statement? La forma en que lo veo, es muy similar a una function agregada normal con GROUP BY:

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

… pero obviamente, alguna function mágica de "bit a bit" en lugar de SUM. Alguien sabe de algo como eso?

(Y para get puntos de bonificación, ¿funciona en Oracle?)

MySQL:

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

Ah, otra de esas preguntas donde encuentro la respuesta 5 minutos después de preguntar … La respuesta aceptada irá a la implementación de MySQL aunque …

He aquí cómo hacerlo con Oracle, como descubrí en el blog de Radino

Usted crea un object …

 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; / 

… y luego define tu propia function agregada

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

Uso:

 SELECT user_id, bitoragg(permissions) FROM perms GROUP BY user_id 

Y puedes hacerlo a bitwise o con …

 FUNCTION BITOR(x IN NUMBER, y IN NUMBER) RETURN NUMBER AS BEGIN RETURN x + y - BITAND(x,y); END; 

Necesitaría conocer los posibles componentes de permiso (1, 2 y 4) apriori (por lo tanto, más difícil de mantener), pero esto es bastante simple y funcionaría:

 SELECT user_id, MAX(BITAND(permissions, 1)) + MAX(BITAND(permissions, 2)) + MAX(BITAND(permissions, 4)) all_perms FROM permissions GROUP BY user_id 

Me interesa encontrar a todos los usuarios que tienen un indicador determinado (por ejemplo, escribir) en CUALQUIER logging

¿Qué pasa con simplemente

 SELECT DISTINCT User_ID FROM Permissions WHERE permissions & 2 = 2