oracle raw type iteration - oracle

I am working with a table that contains a raw(200) field. From my client application I manage to get the value and store it in a byte[] and so that I can loop over it and get all the samples.
My raw data would be like ...
2C2B2E2B2D2C2933283030332B2F2D302F2B272F312E2B2F2F28242A2F322E
... and from there I would like to go from hex to decimal values and get an array such as 44,43,46,43
However, I would like to do a similar thing in a procedure but I don't know how to iterate over a raw field or how to cast it to byte array.
I tried with UTL_RAW.CAST_TO_BINARY_INTEGER but that would only give me the first sample

Given this data ...
SQL> select col1
2 from t23
3 /
COL1
--------------------------------------------------------------------------------
32433242324532423244324332393333323833303330333332423246324433303246324232373246
33313245324232463246323832343241324633323245
SQL>
... a SELECT like this will produce the requisite output...
SQL> select regexp_substr(utl_raw.cast_to_varchar2(col1), '([A-Z0-9]{2})', 1, level)
2 from t23
3 connect by level <= ceil(utl_raw.length(col1)/2)
4 /
REGEXP_SUBSTR(UTL_RAW.CAST_TO_VARCHAR2(COL1),'([A-Z0-9]{2})',1,LEVEL)
--------------------------------------------------------------------------------
2C
2B
2E
2B
...
2B
2F
2F
28
24
2A
2F
32
2E
31 rows selected.
SQL>
Use TO_NUMBER with the 'XX' mask to convert the hex into decimal ...
SQL> select to_number(
2 regexp_substr(utl_raw.cast_to_varchar2(col1), '([A-Z0-9]{2})', 1, level)
3 , 'XX')
4 from t23
5 connect by level <= ceil(utl_raw.length(col1)/2)
6 /
TO_NUMBER(REGEXP_SUBSTR(UTL_RAW.CAST_TO_VARCHAR2(COL1),'([A-Z0-9]{2})',1,LEVEL),
--------------------------------------------------------------------------------
44
43
46
43
45
44
41
...
Finally, to populate an array, and populate it in PL/SQL with the bulk collection syntax:
create type int_nt as table of integer
/
declare
ints int_nt;
begin
select to_number(
regexp_substr(utl_raw.cast_to_varchar2(col1), '([A-Z0-9]{2})', 1, level)
, 'XX')
bulk collect into ints
from t23
connect by level <= ceil(utl_raw.length(col1)/2);
end;
/

Probably there's a more efficient way to solve this but I managed to get my result by using utl_raw.length and utl_raw.substr over my raw data and iterating with an standard plsql loop and converting each substring to decimal with utl_raw.cast_to_binary_integer

Related

PL/SQL MERGE INTO statement ignored

I want to create procedure will move the product (isdiscontinued=1) to another table (Product_discontinued_[NTID]). Structure of the two tables is identical.
PROCEDURE move_table AS
begin
merge into PRODUCTS_DISCONTINUTED b
using PRODUCTS a
on (a.ID = b.ID)
when matched then
update set b.id = a.id,b.productname = a.productname,b.supplierid=a.supplierid,b.unitprice=a.unitprice,
b.package=a.package, b.isdiscontinuted=a.isdiscontinuted
where a.isdiscontinuted = 1
when not matched then
insert (id,productname,supplierid,unitprice,package,isdiscontinuted)
values( a.id,a.productname,a.supplierid,a.unitprice,a.package,a.isdiscontinuted)
where a.isdiscontinuted = 1; END move_table;
I tried to write a procedure to move table PRODUCTS_DISCONTINUTED to PRODUCTS with using MERGE INO statement but it always keep getting the following errors. Could you please help me. Much appreciated.
[enter image description here][2]
error
Terminate merge and remove null;
when not matched then
insert ...
where a.isdicontinuted = 1; --> semi-colon here
-- null; --> remove this
end move_table;
I created tables involved, simply by looking at code you posted. Doing so, procedure gets created:
SQL> CREATE OR REPLACE PROCEDURE move_table
2 AS
3 BEGIN
4 MERGE INTO PRODUCTS_DISCONTINUTED b
5 USING PRODUCTS a
6 ON (a.ID = b.ID)
7 WHEN MATCHED
8 THEN
9 UPDATE SET b.id = a.id,
10 b.productname = a.productname,
11 b.supplierid = a.supplierid,
12 b.unitprice = a.unitprice,
13 b.package = a.package,
14 b.isdiscontinuted = a.isdiscontinuted
15 WHERE a.isdiscontinuted = 1
16 WHEN NOT MATCHED
17 THEN
18 INSERT (id,
19 productname,
20 supplierid,
21 unitprice,
22 package,
23 isdiscontinuted)
24 VALUES (a.id,
25 a.productname,
26 a.supplierid,
27 a.unitprice,
28 a.package,
29 a.isdiscontinuted)
30 WHERE a.isdiscontinuted = 1;
31 END move_table;
32 /
Procedure created.
SQL>
However, error you specified:
ORA-00904: "ISDISCONTINUTED" invalid identifier
means that there's no column whose name is ISDISCONTINUTED. Are you sure you didn't make a typo? Compare table description to code in the procedure - I guess there's a mismatch.

Could not remove unicode character

I have a text string in Oracle table ("NGUYỄN NGỌC HOÀNG"). I have tried to replace the Unicode string (my expected result is "NGUYEN NGOC HOANG") but it didn't work.
Then I tried to convert it to HEX as below: select rawtohex(UnicodeColumn) from TestTable;
Here is the result: 4E 47 55 59 C3 8A CC 83 4E 20 4E 47 4F CC A3 43 20 48 4F 41 CC 80 4E 47
Following the Unicode table: The corresponding characters are: NGUYỄN NGỌC HOÀNG
Could anyone help me this case (Oracle script), I don't have experience about the encoding.
Update 1:
I have tried the solution from Barbaros Özhan but it didn't work
SQL> with tab as ( select '&i_str1' str1 from dual ) 2 select str1,
utl_raw.cast_to_varchar2((nlssort(str1,'nls_sort=binary_ai'))) str2
from tab SQL> / Enter value for i_str1: NGUYỄN NGỌC HOÀNG
SQL> with tab as ( select '&i_str1' str1 from dual )
2 select str1, utl_raw.cast_to_varchar2((nlssort(str1,'nls_sort=binary_ai'))) str2 from tab
SQL> /
Enter value for i_str1: NGUYỄN NGỌC HOÀNG
and you get the desired result.
If you are using Java for connecting to Oracle DBMS, try the Java code below to convert to unaccent character, after that update the row in DBMS.
public static String unAccent(String s) {
String temp = Normalizer.normalize(s, Normalizer.Form.NFD);
Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
return pattern.matcher(temp).replaceAll("").replaceAll("Đ", "D").replace("đ", "");
}
You can try this function to convert to non-accent character:
CREATE OR REPLACE FUNCTION FN_CONVERT_TO_VN
(
STRINPUT IN NVARCHAR2
)
RETURN NVARCHAR2
IS
STRCONVERT NVARCHAR2(32527);
BEGIN
STRCONVERT := TRANSLATE(
STRINPUT, 'áàảãạăắằẳẵặâấầẩẫậđéèẻẽẹêếềểễệíìỉĩịóòỏõọôốồổỗộơớờởỡợúùủũụưứừửữựýỳỷỹỵÁÀẢÃẠĂẮẰẲẴẶÂẤẦẨẪẬĐÉÈẺẼẸÊẾỀỂỄỆÍÌỈĨỊÓÒỎÕỌÔỐỒỔỖỘƠỚỜỞỠỢÚÙỦŨỤƯỨỪỬỮỰÝỲỶỸỴ', 'aaaaaaaaaaaaaaaaadeeeeeeeeeeeiiiiiooooooooooooooooouuuuuuuuuuuyyyyyAAAAAAAAAAAAAAAAADEEEEEEEEEEEIIIIIOOOOOOOOOOOOOOOOOUUUUUUUUUUUYYYYY'
);
RETURN STRCONVERT;
END;

What is the exact NULL value for a field in Oracle?

Title says it all pretty much. What is the exact value that is assigned to a(n) a)Arithmetic b)String c)Logical field to represent NULL, in Oracle DBMS?
Thank you for your time!
Null is the absence of meaning, the absence of value. What gets assigned is null. Not even an ASCII null (ascii value 0) but nothing.
That's why there's a special operation to test for null . This will return false:
...
where col1 = null
We need to test for:
where col1 is null
"we were asked by a professor at uni to find what exactly that value is in these 3 respective cases"
Okay, let's investigate that. Here is a table with two rows:
SQL> create table t42 (
2 type varchar2(10)
3 , colv varchar2(10)
4 , coln number
5 , cold date
6 )
7 /
Table created.
SQL> insert into t42 values ('not null', 'X', 1, sysdate);
1 row created.
SQL> insert into t42 values ('all null', null, null, null);
1 row created.
SQL>Exp
Oracle has a function dump() which shows us the datatype and content of the passed value. Find out more.
What does dump() tell us about our two rows?
SQL> select type
2 , dump(colv) as colv
3 , dump(coln) as coln
4 , dump(cold) as cold
5 from t42;
TYPE COLV COLN COLD
---------- -------------------- -------------------- ----------------------------------
not null Typ=1 Len=1: 88 Typ=2 Len=2: 193,2 Typ=12 Len=7: 120,117,4,29,6,60,44
all null NULL NULL NULL
SQL>
So: the null columns have no data type, no value.
"I don't think dump is suitable for supporting any argument over what "exactly" gets stored to represent a null - because if the expression is null, it simply returns null by definition "
#JeffreyKemp makes a fair point. So let's dip a toe into the internals. The first step is to dump the data block(s);l the dump is written to a trace file:
SQL> conn / as sysdba
Connected.
USER is "SYS"
SQL> select dbms_rowid.rowid_relative_fno(t42.rowid) as fno
2 , dbms_rowid.rowid_block_number(t42.rowid) as blk
3 from a.t42
4 /
FNO BLK
-------- --------
11 132
11 132
SQL> alter system dump datafile 11 block 132;
System altered.
SQL> select value from v$diag_info where name = 'Default Trace File';
VALUE
--------------------------------------------------------------------------------
/home/oracle/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_3275.trc
SQL>
Because T42 is small it fits into only one block. Here is the interesting bit of the dump:
data_block_dump,data header at 0x805664
===============
tsiz: 0x1f98
hsiz: 0x16
pbl: 0x00805664
76543210
flag=--------
ntab=1
nrow=2
frre=-1
fsbo=0x16
fseo=0x1f73
avsp=0x1f5d
tosp=0x1f5d
0xe:pti[0] nrow=2 offs=0
0x12:pri[0] offs=0x1f7f
0x14:pri[1] offs=0x1f73
block_row_dump:
tab 0, row 0, #0x1f7f
tl: 25 fb: --H-FL-- lb: 0x1 cc: 4
col 0: [ 8] 6e 6f 74 20 6e 75 6c 6c
col 1: [ 1] 58
col 2: [ 2] c1 02
col 3: [ 7] 78 75 05 01 02 08 08
tab 0, row 1, #0x1f73
tl: 12 fb: --H-FL-- lb: 0x1 cc: 1
col 0: [ 8] 61 6c 6c 20 6e 75 6c 6c
end_of_block_dump
End dump data blocks tsn: 33 file#: 11 minblk 132 maxblk 132
We can see there are two rows in the table. The first row has entries for four columns; this is the 'not null' row. The second row has only one column: this is the 'all null' row. So, Jeffrey is quite right. All the trailing fields are null so Oracle stores nothing for them.
Answer from APC is fully right, let's give some information on "what does it mean":
Arithmetic: NULL basically means "not defined". Every math operation with NULL (i.e. "not defined") also returns NULL
String: NULL is an empty string, i.e. '' IS NULL returns TRUE - this behavior of Oracle is different to many others RDBMS.
Logical: I assume you mean what happens to BOOLEAN data types. Unlike almost any other programming language in PL/SQL a BOOLEAN variable can have three different states: TRUE, FALSE and NULL. Be aware of this special behavior when you work with BOOLEAN in PL/SQL.
In addition to #APC, in DB there is a something like 'ternary logic' in comparison operations, when we can say that value are equal, not equal and the third is "we don't know", cause of it value absence NULL, and even comparison of to NULL values gives the NULL, meaning that we have no information about operands

How to group by multiple columns and then transpose in Hive

I have some data that I want to group by on multiple columns, perform an aggregation function on, and then transpose into different columns using Hive.
For example, given this input
Input:
hr type value
01 a 10
01 b 20
01 c 50
01 a 30
02 c 10
02 b 90
02 a 80
I want to produce this output:
Output:
hr a_avg b_avg c_avg
01 20 20 50
02 80 90 10
Where there is one distinct column for each distinct type in my input. a_avg corresponds to the average a value for each hour.
How can I do this in Hive? I am guessing I might need to make use of https://github.com/klout/brickhouse/wiki/Collect-UDFs
So far the best I can think of is to use multiple group-by clauses, but that won't transpose the data into multiple columns.
Any ideas?
You don't necessarily need to use Brickhouse, but it will definitely make it easier. Here is what I'm thinking, something like
select hr
, type_map['a'] a_avg
, type_map['b'] b_avg
, type_map['c'] c_avg
from (
select hr
, collect(type, avg_value) type_map -- Brickhouse collect; creates a map
from (
select hr
, type
, avg( value ) avg_value
from db.table
group by hr, type ) x
group by hr ) y

How to update a column of a table using a function in ORACLE

Being a novice in ORACLE and programming in general I have difficulty in updating series of cells in a column of a table in oracle.
The table:
ad soyad not1 not1 not3 BN HN
Ayşe Yılmaz 28 65 82
Melih Türkmen 45 27 56
Cemile Kara 54 65 99
Ragıp Pekkan 62 48 85
Jale Kale 48 75 52
Vehbi Kemal 18 65 63
Mehmet Hamarat 54 62 70
Murat Çokbilir 25 28 32
Harun Reşit 85 84 92
Cemal Yamak 95 23 90
My function :
create or replace
function basariNotu (a NUMBER, b NUMBER, c NUMBER) RETURN NUMBER IS
rbn NUMBER;
BEGIN
rbn:=(a*0.2)+(b*0.2)+(c*0.6);
RETURN rbn;
END basariNotu;
MY code that is supposed to update column 'bn' with rbn returned from the function:
DECLARE
d NUMBER;
e NUMBER;
f NUMBER;
rbn NUMBER;
j NUMBER;
BEGIN
j:=1;
LOOP
SELECT not1 INTO d FROM student;
SELECT not2 INTO e FROM student;
SELECT not3 INTO f FROM student;
basariNotu(d, e, f);
UPDATE student SET bn=rbn WHERE bn= NULL;
j:= j+1;
IF j>10 THEN
EXIT;
END IF;
END LOOP;
END;
You don't have any appropriate WHERE clauses in your queries, and your LOOP has no relationship to the rows being processed. The j counter merely makes the loop do the same action 9 times. Not only that, but your predicate bn= NULL will always evaluate to FALSE so it will never update any rows.
I think you probably want something like this:
FOR r IN (
SELECT student_id, not1, not2, not3
FROM student
WHERE bn IS NULL
) LOOP
rbn := basariNotu(a => r.not1, b => r.not2, c = r.not3);
UPDATE student SET bn=rbn WHERE student_id = r.student_id;
END LOOP;
The above code assumes your table has a unique identifier of some sort such as student_id. If it doesn't, you have more problems to deal with.
However, this is the slow-by-slow (row-by-row) style of programming, the habit of which you need to shake. The above could be done much more simply and efficiently with a single UPDATE statement, e.g.:
UPDATE student
SET bn = basariNotu(a => not1, b => not2, c = not3)
WHERE bn IS NULL;
For even better performance, you would avoid the function call completely, e.g.:
UPDATE student
SET bn = (not1*0.2)+(not2*0.2)+(not3*0.6)
WHERE bn IS NULL;

Resources