简体   繁体   中英

How do I group "or" in pl/sql

I have legacy sql query that selects bit masks (among other data), something like:

1
2
1

How do I group this output like:

1 or 2 or 1 

That should be 3

In order to do bit-wise logic you have to do a "bit" of math. (Bad puns are free around here:-).

Oracle defines the BITAND function. To get a bitwise 'or' you can define your own function as:

FUNCTION BITOR(n1 IN NUMBER, n2 IN NUMBER) 
  RETURN NUMBER
IS
BEGIN
  RETURN n1 - BITAND(n1, n2) + n2;
END BITOR;

And for completeness, BITXOR is

FUNCTION BITXOR(n1 IN NUMBER, n2 IN NUMBER)
  RETURN NUMBER
IS
BEGIN
  RETURN BITOR(n1, n2) - BITAND(n1, n2);
END BITXOR;

Best of luck.

You can use the BITAND operator for AND operation. Using this you can build logic for writing a function for BITOR. Checkout this link http://www.oracledba.co.uk/tips/bitwise_ops.htm

There are no aggregate bit operations in Oracle. One method is an explicit aggregation, bit by bit:

select ((case when max(bitand(bits, 1)) > 0 then 1 else 0 end) +
        (case when max(bitand(bits, 2)) > 0 then 2 else 0 end) +
        (case when max(bitand(bits, 4)) > 0 then 4 else 0 end) +
        (case when max(bitand(bits, 8)) > 0 then 8 else 0 end) +
        (case when max(bitand(bits, 16)) > 0 then 16 else 0 end) +
        (case when max(bitand(bits, 32)) > 0 then 32 else 0 end) +
        (case when max(bitand(bits, 64)) > 0 then 64 else 0 end) +
        (case when max(bitand(bits, 128)) > 0 then 128 else 0 end) +
       ) 

If you wanted an aggregate bitwise AND, then you would use min() instead of max() .

If I understand you correctly, you want an aggregate bit-or function. Oracle doesn't provide one, to my knowledge, so you have to roll your own using their ODCI (Oracle Data Cartridge Interface). Here's a working example:

CREATE OR REPLACE TYPE matt_bitor_aggregate_impl AS OBJECT
(
  result NUMBER,
  CONSTRUCTOR FUNCTION matt_bitor_aggregate_impl(SELF IN OUT NOCOPY matt_bitor_aggregate_impl ) RETURN SELF AS RESULT,  
-- Called to initialize a new aggregation context
-- For analytic functions, the aggregation context of the *previous* window is passed in, so we only need to adjust as needed instead 
-- of creating the new aggregation context from scratch
  STATIC FUNCTION ODCIAggregateInitialize (sctx IN OUT matt_bitor_aggregate_impl) RETURN NUMBER,
-- Called when a new data point is added to an aggregation context  
  MEMBER FUNCTION ODCIAggregateIterate (self IN OUT matt_bitor_aggregate_impl, value IN NUMBER ) RETURN NUMBER,
-- Called to return the computed aggragate from an aggregation context
  MEMBER FUNCTION ODCIAggregateTerminate (self IN matt_bitor_aggregate_impl, returnValue OUT NUMBER, flags IN NUMBER) RETURN NUMBER,
-- Called to merge to two aggregation contexts into one (e.g., merging results of parallel slaves) 
  MEMBER FUNCTION ODCIAggregateMerge (self IN OUT matt_bitor_aggregate_impl, ctx2 IN matt_bitor_aggregate_impl) RETURN NUMBER --,
);

/

CREATE OR REPLACE TYPE BODY matt_bitor_aggregate_impl IS

CONSTRUCTOR FUNCTION matt_bitor_aggregate_impl(SELF IN OUT NOCOPY matt_bitor_aggregate_impl ) RETURN SELF AS RESULT IS
BEGIN
  SELF.result := null;
  RETURN;
END;


STATIC FUNCTION ODCIAggregateInitialize (sctx IN OUT matt_bitor_aggregate_impl) RETURN NUMBER IS
BEGIN
  sctx := matt_bitor_aggregate_impl ();
  RETURN ODCIConst.Success;
END;


MEMBER FUNCTION ODCIAggregateIterate (self IN OUT matt_bitor_aggregate_impl, value IN NUMBER ) RETURN NUMBER IS
BEGIN
  IF self.result IS NULL THEN
    self.result := value;
  ELSE
    -- Logic for bitwise OR
    -- see also: http://www.oracledba.co.uk/tips/bitwise_ops.htm
    self.result := self.result - BITAND(self.result, value) + value;
  END IF;
  RETURN ODCIConst.Success;
END;

MEMBER FUNCTION ODCIAggregateTerminate (self IN matt_bitor_aggregate_impl, returnValue OUT NUMBER, flags IN NUMBER) RETURN NUMBER IS
BEGIN
  returnValue := result;
  RETURN ODCIConst.Success;
END;

MEMBER FUNCTION ODCIAggregateMerge (self IN OUT matt_bitor_aggregate_impl, ctx2 IN matt_bitor_aggregate_impl) RETURN NUMBER IS
BEGIN
   -- Logic for bitwise OR
   -- see also: http://www.oracledba.co.uk/tips/bitwise_ops.htm
   self.result := self.result - BITAND(self.result, ctx2.result) + ctx2.result;
  RETURN ODCIConst.Success;
END;

END;
/

-- Now that you have a TYPE to implement the logic, here is where you define the new aggregate function
CREATE OR REPLACE FUNCTION matt_bitor_aggregate ( input NUMBER) RETURN NUMBER
PARALLEL_ENABLE AGGREGATE USING matt_bitor_aggregate_impl;
/

-- Here's a simple test with your test data set...
with test_data as ( 
  SELECT 1 a FROM dual UNION ALL 
  select 2 from dual union all 
  select 1 from dual  
  )
select matt_bitor_aggregate(a)
from   test_data;

-- Here is a more complex test that also highlights the fact that you can use ODCI custom aggregates with window clauses.
with test_data as ( 
  SELECT 1 a FROM dual UNION ALL 
  select 2 from dual union all 
  select 1 from dual union all 
  select 16 from dual union all 
  SELECT 18 from dual)
select a, matt_bitor_aggregate(a) over ( partition by null order by rownum rows between 1 preceding and 1 following ) from
test_data;

As of Oracle 20c, you can do bitwise aggregates using the following functions:

  1. BIT_AND_AGG
  2. BIT_OR_AGG
  3. BIT_XOR_AGG

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM