tsol transporte grupo computrabajo colombia sql mysql oracle group-by aggregate-functions

sql - transporte - ¿Es posible realizar una función de grupo bit a bit?



grupo bit computrabajo (5)

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

¿Qué pasa con simplemente

SELECT DISTINCT User_ID FROM Permissions WHERE permissions & 2 = 2

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 conjunto de banderas (por ejemplo, escribir) en CUALQUIER registro. Para hacer esto en una consulta, calculé que si ordenaba TODOS los permisos del usuario juntos obtendría un valor único que es la "suma total" de sus permisos:

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

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

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

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

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

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


MySQL:

SELECT user_id, BIT_OR(permissions) as all_perms FROM permissions 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;


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 objeto ...

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 función 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


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