I am in this situation, I cannot validate the bit for the print permission. Unfortunately I can't have a bitmask with a single bit lit. Can you give me some suggestions?
SELECT
DECODE(BITAND(00000000100000100000000000000001, 1), 1, '1', '0') AS READ,
DECODE(BITAND(00000000100000100000000000000001, 131072), 131072, '1', '0') AS COPY,
DECODE(BITAND(00000000100000100000000000000001, 8388608), 8388608, '1', '0') AS PRINT
FROM
DUAL
The result is the following
R C P
- - -
1 1 0
Can you give me some suggestions?
The BIT_AND function has both arguments as numbers, and there is no bit vector.
For example:
select bin_to_num(0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1) from dual;
OUTPUT>
8519681
with
datum as
(select bin_to_num(0,0,0,0,0,0,0,0,1/*print*/,0,0,0,0,0,1/*copy*/,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1/*read*/) val from dual)
select
decode(bitand(val, 1), 1, '1', '0') as read,
decode(bitand(val, 131072), 131072, '1', '0') as copy,
decode(bitand(val, 8388608), 8388608, '1', '0') as print
from datum
Related
I'm trying to use regexp_subst to split a delimited string. I'm running into an issue when delimited fields are null. The regexp_substr ignores the nulls and moves to the next occurrence of the delimiter. Is there a way to do this with regexp_substr? If not, what alternative do you use?
--Expecting hello, gets hello
select regexp_substr('hello##world', '[^#]+', 1, 1)
from dual;
--Expecting null, gets world
select regexp_substr('hello##world', '[^#]+', 1, 2)
from dual;
--Expecting world, gets null
select regexp_substr('hello##world', '[^#]+', 1, 3)
from dual;
EDIT: tried this, but it works only with | which isn't an option
Answering based on Matbailie's input in above comment
select regexp_substr('hello##world', '(.*?)(#|$)', 1, 1,NULL,1)
from dual
union all
--Expecting null, gets null
select regexp_substr('hello##world', '(.*?)(#|$)', 1, 2,NULL,1)
from dual
union all
--Expecting world, gets world
select regexp_substr('hello##world', '(.*?)(#|$)', 1, 3,NULL,1)
from dual;
You do not need regular expressions. It can be done with simple (and faster) string functions in a recursive sub-query:
WITH data (value) AS (
SELECT 'hello##world' FROM DUAL
),
bounds (value, start_pos, end_pos) AS (
SELECT value,
1,
INSTR(value, '#', 1)
FROM data
UNION ALL
SELECT value,
end_pos + 1,
INSTR(value, '#', end_pos + 1)
FROM bounds
WHERE end_pos > 0
)
SEARCH DEPTH FIRST BY value SET order_id
SELECT CASE end_pos
WHEN 0
THEN SUBSTR(value, start_pos)
ELSE SUBSTR(value, start_pos, end_pos - start_pos)
END AS item
FROM bounds;
Which outputs:
ITEM
hello
null
world
Or, if you want the data in columns (rather than rows):
WITH data (value) AS (
SELECT 'hello##world' FROM DUAL
),
bounds (value, pos1, pos2) AS (
SELECT value,
INSTR(value, '#', 1, 1),
INSTR(value, '#', 1, 2)
FROM data
)
SELECT SUBSTR(value, 1, pos1 - 1) AS item1,
SUBSTR(value, pos1 + 1, pos2 - pos1 - 1) AS item2,
SUBSTR(value, pos2 + 1) AS item3
FROM bounds
Which outputs:
ITEM1
ITEM2
ITEM3
hello
null
world
If you did want to use (slower) regular expressions then:
WITH data (value) AS (
SELECT 'hello##world' FROM DUAL
)
SELECT item
FROM data d
CROSS JOIN LATERAL(
SELECT REGEXP_SUBSTR( d.value, '(.*?)(#|$)', 1, LEVEL, NULL, 1) AS item
FROM DUAL
CONNECT BY LEVEL < REGEXP_COUNT( d.value, '(.*?)(#|$)')
)
or, for columns:
WITH data (value) AS (
SELECT 'hello##world' FROM DUAL
)
SELECT REGEXP_SUBSTR(value, '(.*?)(#|$)', 1, 1, NULL, 1) AS item1,
REGEXP_SUBSTR(value, '(.*?)(#|$)', 1, 2, NULL, 1) AS item2,
REGEXP_SUBSTR(value, '(.*?)(#|$)', 1, 3, NULL, 1) AS item3
FROM data
(Which both have the same output as above)
db<>fiddle here
I have 3 matrix:
T_01 = ['cosd*t1', '-sind*t1', '0', 'd1*cosd*t1'; 'sind*t1', 'cosd*t1', '0', 'd1*sind*t1'; '0', '1', '1', '0'; '0', '0', '0', '1']
T_12 = ['cosd*t2', '-sind*t2', '0', 'd2*cosd*t2'; 'sind*t2', 'cosd*t2', '0', 'd2*sind*t2'; '0', '1', '1', '0'; '0', '0', '0', '1']
T_23 = ['cosd*t3', '-sind*t3', '0', 'd3*cosd*t3'; 'sind*t3', 'cosd*t3', '0', 'd3*sind*t3'; '0', '1', '1', '0'; '0', '0', '0', '1']
I need to make a symbolic multiplication, so I'm trying:
mulf(T_01,T_12,T_23)
But I get this error:
!--error 39
mulf: Quantidade incorreta de argumentos de entrada: esperava-se 2.
What is happening?
Obs.: Sorry for my english.
If what you want is to get the symbolic multiplication of two matrix, you'll have to implement such function. Here I've implemented three functions that together can perform what you want:
function s = scaProd(a,b)
//escalar product of two vectors
//using recursion
if (a == [] | b == []) then
s = ""
elseif (max(size(a)) ~= max(size(b))) | ...
(min(size(a)) ~= min(size(b))) | ...
(min(size(a)) ~= 1) then
error("vectorMulf: Wrong dimensions")
else
s = addf( mulf(a(1), b(1)) , scaProd(a(2:$), b(2:$)) )
end
endfunction
function s = matrixMulf(a,b)
//matrix multiplication
acols = size(a,'c');
brows = size(b,'r');
if acols ~= brows then
error("matrixMulf: Wrong dimensions")
end
arows = size(a,'r');
bcols = size(b,'c');
s = string(zeros(arows,bcols));
for i = 1 : arows
for j = 1 : bcols
s(i,j) = scaProd(a(i,:),b(:,j)');
end
end
endfunction
function s = addP(a)
//encolses each element of a in a pair of parenthesis
s = string(zeros(a));
for i = 1 : size(a,'r')
for j = 1 : size(a,'c')
s(i,j) = "(" + a(i,j) + ")"
end
end
endfunction
Here is an example of it's output. Test code:
A = [1 2; 3 4];
B = [5 6; 7 8];
C = [9 0; 1 2];
disp(A*B*C)
As = string(A);
Bs = string(B);
Cs = string(C);
disp(matrixMulf(As,addP(matrixMulf(Bs, Cs))))
Console output:
193. 44.
437. 100.
!1*(5*9+6*1)+2*(7*9+8*1) 1*(5*0+6*2)+2*(7*0+8*2) !
! !
!3*(5*9+6*1)+4*(7*9+8*1) 3*(5*0+6*2)+4*(7*0+8*2) !
For the result you want, you should do:
Enclose every term of each of your matrices with parenthesis using addP()
Perform the symbolic multiplication like matrixMulf(t1,addP(matrixMulf(t2,t3))), where t1, t2, t3 are the enclosed versions of your matrices.
And two final notes:
It is important to use addP at each multiplication step to get the correct result. You can check that by removing the ( and ) in the example I gave: the result won't be correct.
The functions mulf and addf are not available on Scilab 6.0.0. So remember you won't be able to use them if you upgrade your Scilab to the current stable version.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I face this questing in an interview. Please let me know possible answer for this questing.
We have a matrix like 3 X 3, 5 X 5 or 7 X 7. In mid we do have X(represent zombie) and 0(void or blank) or 1(Human) at all nodes. X created all adjacent human nodes zombie in a minute.
So how much time it will take to create all matrix zombie.
Don't let the terminology fool you: this is a graph problem. I assume that a zombie can also reach the humans that are diagonally adjacent to it.
If you conduct a Breadth first search from the "Zombie point", you will be able to determine that time (if it exists). This is basically how you proceed: (code sample in Python)
matrix = [['1', '0', '0'],['1', 'X', '1'],['0', '0', '0']]
mid = len(matrix)//2
yet_to_explore = [(mid,mid,0)]
explored_set = {} # This is a hashset of explored nodes
while [] != yet_to_explore:
cur_vertex = yet_to_explore.pop(0)
x = cur_vertex[0]
y = cur_vertex[1]
if (x,y) in explored_set:
continue
explored_set[(x,y)] = cur_vertex[2]
matrix[x][y] = 'X'
for i in range(-1,2):
if 0 > x + i or len(matrix) <= x + i:
continue
for j in range(-1,2):
if 0 > y + j or len(matrix) <= y + j:
continue
elif 0 == i and 0 == j:
continue
elif matrix[x+i][y+j]=='1':
yet_to_explore.append((x+i, y+j, cur_vertex[2]+1))
# If your matrix contains a '1' after the BFS this means some human were not reachable (they are isolated) -> the desired time does not exist since not every human can be a zombie
# Else the time you are looking for is the following result:
time = max(list(explored_set.values()))
An example where there is a survivor:
matrix = [['0', '0', '0', '0', '0', '0', '0'],
['1', '1', '1', '1', '0', '0', '0'], # The human on the left will be contamined within 4 min
['0', '0', '0', '1', '0', '0', '0'],
['1', '0', '0', 'X', '0', '0', '0'], # The human on the left will survive
['0', '0', '1', '0', '1', '0', '0'],
['0', '0', '1', '0', '0', '1', '0'],
['0', '1', '0', '0', '0', '0', '1']] # The human on the right will be contamined within 3 min
The search for hypothetical survivors is left as an exercise.
select rtrim(regexp_substr (str, '[^|]*(.|$)', 1, level), '|') ASPLIT
from
(select 'str 1|str 2|str 3' as str from dual)
connect by level <= length (regexp_replace (str, '[^|]+')) + 1
str 1 str 2 str 3
How to alter the parser separator ', ' ?
'str 1, str 2, str 3'
You can just change the delimiter in the pattern:
select rtrim(regexp_substr (str, '[^,]*(.|$)', 1, level), ',') ASPLIT
from
(select 'str 1, str 2, str 3' as str from dual)
connect by level <= length (regexp_replace (str, '[^,]+')) + 1;
Note that you do not want to change the one in the grouping, (.|$); in that context it's an OR operator not a literal character.
It's simpler to use the same pattern in the substring as you do in the replace (but note Gary_W's warning about this losing empty values with this pattern):
select trim(regexp_substr (str, '[^,]+', 1, level)) ASPLIT
from (select 'str 1, str 2, str 3' as str from dual)
connect by level <= length (regexp_replace (str, '[^,]+')) + 1;
ASPLIT
-------------------
str 1
str 2
str 3
But since you have spaces after the commas, you need to eliminate those; the simplest way is to get rid of leading and trailing spaces with trim. This also shows a variation on the connect by limit but either works (again, note the warning about this pattern):
select trim(regexp_substr (str, '[^,]+', 1, level)) ASPLIT
from (select 'str 1, str 2, str 3' as str from dual)
connect by regexp_substr (str, '[^,]+', 1, level) is not null;
ASPLIT
-------------------
str 1
str 2
str 3
I must point out that using the regex of the format '[^,]+' to parse a string will give invalid results if there is a NULL element in the list and the position of the element in the list is important. Consider this where the 2nd element is NULL. The results make it seem the 2nd element is 'str 3' where really the 2nd element is NULL.
SQL> select trim(regexp_substr (str, '[^,]+', 1, level)) ASPLIT
from (select 'str 1,, str 3' as str from dual)
connect by level <= length (regexp_replace (str, '[^,]+')) + 1;
ASPLIT
-------------
str 1
str 3
Here's another way that handles the NULL list element:
SQL> select trim(regexp_substr (str, '(.*?)(,|$)', 1, level, NULL, 1)) ASPLIT
from (select 'str 1,, str 3' as str from dual)
connect by level <= regexp_count(str, ',') + 1;
ASPLIT
-------------
str 1
str 3
SQL>
See this post for more info too: Split comma separated values to columns in Oracle
I am trying to create an exclusive or statement within an in clause. For example
WHERE ACCOUNT IN (1,2,3) XOR ACCOUNT IN (3,4) XOR ACCOUNT IN (5,6)
The only reference materials I can find do not facilitate using an IN clause. TIA.
Edit - Clarification :
DDL:
CREATE TABLE EXAMPLE
(
CONTRACT VARCHAR2(1),
ID_NUMBER NUMBER,
ACCOUNT NUMBER,
AMOUNT_1 NUMBER,
AMOUNT_2 NUMBER
);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('A', 1, 100, 5, NULL);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('A', 2, 101, NULL, 5);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('A', 3, 200, 2, NULL);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('B', 4, 100, 7, NULL);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('B', 5, 100, 3, NULL);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('B', 6, 101, NULL, 10);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('B', 7, 200, 2, NULL);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('C', 8, 200, 10, NULL);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('C', 9, 200, 5, NULL);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('C', 10, 201, NULL, 15);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('C', 11, 300, 6, NULL);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('C', 12, 301, NULL, 6);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('D', 13, 100, NULL, -5);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('D', 14, 100, NULL, 5);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('D', 15, 300, 7, 3);
INSERT INTO EXAMPLE (CONTRACT, ID_NUMBER, ACCOUNT, AMOUNT_1, AMOUNT_2)
VALUES ('D', 16, 200, NULL, 4);
My query:
SELECT * FROM
(
SELECT
A.CONTRACT,
COUNT(NVL(ID_NUMBER,1)) AS ID_NUMBER_COUNT,
LISTAGG(ID_NUMBER, ', ') WITHIN GROUP(ORDER BY CONTRACT) AS ID_NUMBERS,
SUM(NVL(AMOUNT_1,0)) AS AMOUNT_1_SUM,
SUM(NVL(AMOUNT_2,0)) AS AMOUNT_2_SUM
FROM EXAMPLE A
WHERE 1=1
AND NOT (NVL(AMOUNT_1,0) = NVL(AMOUNT_2,0))
GROUP BY CUBE(CONTRACT,ACCOUNT)
) A
WHERE 1=1
AND NVL(A.AMOUNT_1_SUM,0) = NVL(A.AMOUNT_2_SUM,0)
AND CONTRACT IS NOT NULL
The CUBE function may seem like overkill for this example, but my actual table has several more descriptor columns that necessitates searching across the combinations.
If you run the query on the above table, without any IN clause to limit the accounts, you will not receive the true population of records that are offsets (should clarify that they only sum to zero if they are in the same column, other wise an offset will occur across both columns where the aggregated amounts are equal).
The true population of records that I am aiming to capture is:
-On contract A, ID Numbers 1 and 2
-On contract B, ID Number 4,5, and 6
-On contract C, all ID Numbers
-On contract D, all ID Numbers
The query as it stands currently can capture all ID numbers across contracts C and D, however there are records in contracts A and B that will not come back as a valid result unless the accounts are limited.
-Limiting account to IN (100,101) will yield the ID numbers from A and B that I aim to capture. The caveat is that there are ~20 combinations of accounts in my full population that must be searched.
-There will never be an offset that occurs between two different contracts. I handle this in the query on the full population by using GROUPING_ID, then just excluding anywhere the Contract field is blank.
-As a last resort, I can use a UNION statement, but would like to do without using one.
-The only other thing I can currently think to do is to define the sets of accounts somewhere before I run the query, then just run a FOR loop for each set.
Thank you!
The equivalent of A XOR B is ( A AND NOT B ) OR ( B AND NOT A ) which would make your query something like this:
WHERE ( ACCOUNT IN (1,2,3) AND ACCOUNT NOT IN (3,4,5,6) )
OR ( ACCOUNT IN (3,4) AND ACCOUNT NOT IN (1,2,3,5,6) )
OR ( ACCOUNT IN (5,6) AND ACCOUNT NOT IN (1,2,3,3,4) )
However, the question does not really make sense as ACCOUNT cannot have multiple values so (apart from 3 which appears in multiple sets) you appear to be testing for the equivalent of A XOR NOT A which will always be true (when ACCOUNT <> 3).
Given this, the logic above will simplify to:
WHERE ACCOUNT IN (1,2,4,5,6)
Edit - Following the clarification of the question:
Oracle Setup:
I renamed the Amount_1 and Amount_2 columns to Credit and Debit
CREATE TABLE EXAMPLE( CONTRACT, ID_NUMBER, ACCOUNT, CREDIT, DEBIT ) AS
SELECT 'A', 1, 100, 5, NULL FROM DUAL UNION ALL
SELECT 'A', 2, 101, NULL, 5 FROM DUAL UNION ALL
SELECT 'A', 3, 200, 2, NULL FROM DUAL UNION ALL
SELECT 'B', 4, 100, 7, NULL FROM DUAL UNION ALL
SELECT 'B', 5, 100, 3, NULL FROM DUAL UNION ALL
SELECT 'B', 6, 101, NULL, 10 FROM DUAL UNION ALL
SELECT 'B', 7, 200, 2, NULL FROM DUAL UNION ALL
SELECT 'C', 8, 200, 10, NULL FROM DUAL UNION ALL
SELECT 'C', 9, 200, 5, NULL FROM DUAL UNION ALL
SELECT 'C', 10, 201, NULL, 15 FROM DUAL UNION ALL
SELECT 'C', 11, 300, 6, NULL FROM DUAL UNION ALL
SELECT 'C', 12, 301, NULL, 6 FROM DUAL UNION ALL
SELECT 'D', 13, 100, NULL, -5 FROM DUAL UNION ALL
SELECT 'D', 14, 100, NULL, 5 FROM DUAL UNION ALL
SELECT 'D', 15, 300, 7, 3 FROM DUAL UNION ALL
SELECT 'D', 16, 200, NULL, 4 FROM DUAL UNION ALL
SELECT 'E', 17, 100, 3, NULL FROM DUAL UNION ALL
SELECT 'E', 18, 200, NULL, 4 FROM DUAL;
CREATE OR REPLACE TYPE TransactionObj AS OBJECT(
ID_NUMBER INT,
ACCOUNT INT,
VALUE INT
);
/
CREATE OR REPLACE TYPE TransactionTable AS TABLE OF TransactionObj;
/
CREATE OR REPLACE FUNCTION getMaxZeroSum(
Transactions TransactionTable
) RETURN TransactionTable
AS
zeroSumTransactions TransactionTable := Transactiontable();
bitCount INT;
valueSum INT;
maxBitCount INT := 0;
valueMax INT := 0;
BEGIN
IF Transactions IS NULL OR Transactions IS EMPTY THEN
RETURN zeroSumTransactions;
END IF;
FOR i IN 1 .. POWER( 2, Transactions.COUNT ) - 1 LOOP
bitCount := 0;
valueSum := 0;
FOR j IN 1 .. Transactions.COUNT LOOP
IF BITAND( i, POWER( 2, j - 1 ) ) > 0 THEN
valueSum := valueSum + Transactions(j).VALUE;
bitCount := bitCount + 1;
END IF;
END LOOP;
IF valueSum = 0 AND bitCount > maxBitCount THEN
maxBitCount := bitCount;
valueMax := i;
END IF;
END LOOP;
IF maxBitCount > 0 THEN
zeroSumTransactions.EXTEND( maxBitCount );
bitCount := 0;
FOR j IN 1 .. Transactions.COUNT LOOP
IF BITAND( valueMax, POWER( 2, j - 1 ) ) > 0 THEN
bitCount := bitCount + 1;
zeroSumTransactions(bitCount) := transactions(j);
END IF;
END LOOP;
END IF;
RETURN zeroSumTransactions;
END;
/
Query:
SELECT zs.Contract,
LISTAGG( t.ID_NUMBER, ',' ) WITHIN GROUP ( ORDER BY ID_NUMBER ) AS ids,
LISTAGG( t.ACCOUNT, ',' ) WITHIN GROUP ( ORDER BY ID_NUMBER ) AS accounts
FROM (
SELECT CONTRACT,
getMaxZeroSum( CAST( COLLECT( TransactionObj( ID_NUMBER, ACCOUNT, NVL( CREDIT, 0 ) - NVL( DEBIT, 0 ) ) ) AS TransactionTable ) ) AS Transactions
FROM EXAMPLE
WHERE NVL( CREDIT, 0 ) <> NVL( DEBIT, 0 )
GROUP BY CONTRACT
) zs,
TABLE( zs.Transactions ) (+) t
GROUP BY Contract;
Output:
CONTRACT IDS ACCOUNTS
-------- -------------- --------------------
A 1,2 100,101
B 4,5,6 100,100,101
C 8,9,10,11,12 200,200,201,300,301
D 13,14,15,16 100,100,300,200
E NULL NULL
The getMaxZeroSum function could almost certainly be improved to consider the transactions in order of least number of items excluded through to all-but-two excluded and then to return as soon as it finds a zero sum (however, I went for having an easy to write function as a demonstration of how it could be done over a performant one). But however you write it I can't see a way that isn't O(n(2^n)) where n is the number of transactions for a given contract.