最有效的解决方案可能是运行直接 SQL 聚合。由于权限是有限的,因此存在给定数量的个人权限 (N)。您可以在 N 列中分解每个权限,聚合(使用MAX
)并在之后重新组合权限:
p1 = sign(BitAnd(permissions, 2^0))
p2 = sign(BitAnd(permissions, 2^1))
...
P1 = MAX(p1)
P2 = MAX(P2)
...
Permissions = 2^0 * P1 + 2^1 * P2 + ... + 2^(N-1) * PN
但这会很乏味,并且在添加新权限时必须重写查询:
SQL> select name,
2 power(2, 0) * MAX(sign(BitAnd(permissions, power(2, 0))))
3 + power(2, 1) * MAX(sign(BitAnd(permissions, power(2, 1))))
4 + power(2, 2) * MAX(sign(BitAnd(permissions, power(2, 2))))
5 + power(2, 3) * MAX(sign(BitAnd(permissions, power(2, 3))))
6 + power(2, 4) * MAX(sign(BitAnd(permissions, power(2, 4))))
7 + power(2, 5) * MAX(sign(BitAnd(permissions, power(2, 5))))
8 + power(2, 6) * MAX(sign(BitAnd(permissions, power(2, 6))))
9 + power(2, 7) * MAX(sign(BitAnd(permissions, power(2, 7))))
10 + power(2, 8) * MAX(sign(BitAnd(permissions, power(2, 8))))
11 permissions
12 from cats
13 group by name;
NAME PERMISSIONS
--------------- -----------
Carl 15
Steve 23
相反,我建议您编写自己的用户定义聚合(受Tom Kyte 的这篇文章的启发——在 9ir2 上测试):
SQL> create or replace type bin_agg_type as object
2 (
3 total NUMBER,
4
5 static function
6 ODCIAggregateInitialize(sctx IN OUT bin_agg_type )
7 return number,
8
9 member function
10 ODCIAggregateIterate(self IN OUT bin_agg_type ,
11 value IN NUMBER)
12 return number,
13
14 member function
15 ODCIAggregateTerminate(self IN bin_agg_type ,
16 returnValue OUT NUMBER,
17 flags IN number)
18 return number,
19
20 member function
21 ODCIAggregateMerge(self IN OUT bin_agg_type,
22 ctx2 IN bin_agg_type)
23 return number
24 );
25 /
Type created.
SQL> create or replace type body bin_agg_type
2 is
3
4 static function ODCIAggregateInitialize(sctx IN OUT bin_agg_type )
5 return number
6 is
7 begin
8 sctx := bin_agg_type ( 0 );
9 return ODCIConst.Success;
10 end;
11
12 member function ODCIAggregateIterate(self IN OUT bin_agg_type ,
13 value IN NUMBER)
14 return number
15 is
16 begin
17 self.total := self.total + value - BitAND(self.total, value);
18 return ODCIConst.Success;
19 end;
20
21 member function ODCIAggregateTerminate(self IN bin_agg_type ,
22 returnValue OUT NUMBER,
23 flags IN number)
24 return number
25 is
26 begin
27 returnValue := total;
28 return ODCIConst.Success;
29 end;
30
31 member function ODCIAggregateMerge(self IN OUT bin_agg_type ,
32 ctx2 IN bin_agg_type )
33 return number
34 is
35 begin
36 self.total := self.total+ctx2.total - BitAND(self.total, ctx2.total);
37 return ODCIConst.Success;
38 end;
39
40
41 end;
42 /
Type body created.
SQL> CREATE or replace
2 FUNCTION BitOr_Agg(input NUMBER)
3 RETURN NUMBER
4 PARALLEL_ENABLE AGGREGATE USING bin_agg_type ;
5 /
Function created.
让我们称之为:
SQL> SELECT name, bitor_agg(permissions) from cats group by name;
NAME BITOR_AGG(PERMISSIONS)
--------------- ----------------------
Carl 15
Steve 23
我很想知道哪个是最快的。