Folks!
Does somebody know an Oracle built-in datatypes system dictionary view?
Example:
SELECT DUMP ('HASAN') FROM DUAL;
returns
Typ=96 Len=5: 72,65,83,65,78
Oracle documentation says that it is CHAR or NCHAR datatype.
But is there a view, where I can find this datatype by code returned (Typ=96)?
Does it exist at all?
SELECT t.typecode, name
FROM sys.type$ t, sys.obj$ o
WHERE t.toid = o.oid$ and t.typecode = 96;
You can also check source code of DBMS_TYPES package
select TEXT
from dba_source
where name = 'DBMS_TYPES'
and regexp_like(text, 'TYPECODE');
TYPECODE_DATE PLS_INTEGER := 12;
TYPECODE_NUMBER PLS_INTEGER := 2;
TYPECODE_RAW PLS_INTEGER := 95;
TYPECODE_CHAR PLS_INTEGER := 96;
TYPECODE_VARCHAR2 PLS_INTEGER := 9;
TYPECODE_VARCHAR PLS_INTEGER := 1;
TYPECODE_MLSLABEL PLS_INTEGER := 105;
TYPECODE_BLOB PLS_INTEGER := 113;
TYPECODE_BFILE PLS_INTEGER := 114;
TYPECODE_CLOB PLS_INTEGER := 112;
TYPECODE_CFILE PLS_INTEGER := 115;
TYPECODE_TIMESTAMP PLS_INTEGER := 187;
TYPECODE_TIMESTAMP_TZ PLS_INTEGER := 188;
TYPECODE_TIMESTAMP_LTZ PLS_INTEGER := 232;
TYPECODE_INTERVAL_YM PLS_INTEGER := 189;
TYPECODE_INTERVAL_DS PLS_INTEGER := 190;
TYPECODE_REF PLS_INTEGER := 110;
TYPECODE_OBJECT PLS_INTEGER := 108;
TYPECODE_VARRAY PLS_INTEGER := 247; /* COLLECTION TYPE */
TYPECODE_TABLE PLS_INTEGER := 248; /* COLLECTION TYPE */
TYPECODE_NAMEDCOLLECTION PLS_INTEGER := 122;
TYPECODE_OPAQUE PLS_INTEGER := 58; /* OPAQUE TYPE */
TYPECODE_NCHAR PLS_INTEGER := 286;
TYPECODE_NVARCHAR2 PLS_INTEGER := 287;
TYPECODE_NCLOB PLS_INTEGER := 288;
TYPECODE_BFLOAT PLS_INTEGER := 100;
TYPECODE_BDOUBLE PLS_INTEGER := 101;
TYPECODE_UROWID PLS_INTEGER := 104;
Note, numbers in DBMS_TYPES are related to PL/SQL. However, DUMP is a SQL function which you cannot use in PL/SQL. Thus these numbers are slightly different.
There's DBA_TYPEs, which has a predefined column, e.g.:
SELECT * FROM dba_types WHERE predefined = 'YES';
That seems to have a few of the obvious types (e.g. NUMBER, VARCHAR2, etc) in it, but I wouldn't like to say that's exclusive (for example, the ANYDATA datatype has predefined = NO).
Anyway, it ought to give you an idea of where to look, although why you'd want to I'm not sure?
N.B. If you want to see a list of the dictionary tables, you can do:
select * from dictionary;
You can filter as appropriate, if you can't remember the exact table name!
Related
I have large text around 20000 I need convert to UTF8.
select convert('large text','UTF8') from dual
I get error:
ORA-01704: string literal too long
Try this get another error
declare
v_hugetxt varchar2(32767);
begin
v_hugetxt:='huge text'
select convert(v_hugetxt,'UTF8') into v_hugetxt
from dual;
end;
I get error
ORA-01460: unimplemented or unreasonable conversion requested tips ยท
Incompatible character sets can cause an ORA-01460
I found solution but worked
FYI
create or replace function v_blobtoclob(v_blob_in in blob) return clob is
v_file_clob clob;
v_file_size integer := dbms_lob.lobmaxsize;
v_dest_offset integer := 1;
v_src_offset integer := 1;
v_blob_csid number := dbms_lob.default_csid;
v_lang_context number := dbms_lob.default_lang_ctx;
v_warning integer;
v_length number;
begin
dbms_lob.createtemporary(v_file_clob, true);
dbms_lob.converttoclob(v_file_clob,
v_blob_in,
v_file_size,
v_dest_offset,
v_src_offset,
v_blob_csid,
v_lang_context,
v_warning);
return v_file_clob;
exception
when others then
dbms_output.put_line('Error found');
end;
CREATE OR REPLACE FUNCTION clob_to_blob (p_clob CLOB, p_charsetname VARCHAR2)
RETURN BLOB
AS
l_lang_ctx INTEGER := DBMS_LOB.default_lang_ctx;
l_warning INTEGER;
l_dest_offset NUMBER := 1;
l_src_offset NUMBER := 1;
l_return BLOB;
BEGIN
DBMS_LOB.createtemporary (l_return, FALSE);
DBMS_LOB.converttoblob (
l_return,
p_clob,
DBMS_LOB.lobmaxsize,
l_dest_offset,
l_src_offset,
CASE WHEN p_charsetname IS NOT NULL THEN NLS_CHARSET_ID (p_charsetname) ELSE DBMS_LOB.default_csid END,
l_lang_ctx,
l_warning);
RETURN l_return;
END;
declare
v_hugetxt clob;
v_hugetxt2 blob;
v_hugetxt3 clob;
offset int;
clobsize number;
begin
v_hugetxt:='huge text';
select bnf.clob_to_blob(v_hugetxt,'UTF8') into v_hugetxt2 from dual;
select bnf.v_blobtoclob(v_hugetxt2) into v_hugetxt3 from dual;
dbms_output.put_line('Print CLOB');
offset:=1;
loop
exit when offset > dbms_lob.getlength(v_hugetxt3);
dbms_output.put_line(dbms_lob.substr(v_hugetxt3, 255, offset));
offset := offset + 255;
end loop;
DBMS_OUTPUT.PUT_LINE('clob out = ' || v_hugetxt3);
end;
That's it
Here is the function:
create or replace FUNCTION FUNC_PART(
p_TEXT varchar2,
p_COLUMN number,
p_SEPARATOR varchar2
) RETURN varchar2 AS
v_POS_ number;
v_POS2 number;
V_COLUMN NUMBER;
BEGIN
V_COLUMN:=p_COLUMN;
v_POS_ := 1;
v_POS2 := INSTR(p_TEXT, p_SEPARATOR, v_POS_);
WHILE (V_COLUMN >1 AND v_POS2> 0) LOOP
v_POS_ := v_POS2 + 1;
v_POS2 := INSTR(p_TEXT, p_SEPARATOR, v_POS_);
V_COLUMN :=V_COLUMN - 1;
END LOOP;
IF V_COLUMN > 1 THEN
v_POS_ := LENGTH(RTRIM(p_TEXT)) + 1;
END IF;
IF v_POS2 = 0 THEN
v_POS2 := LENGTH(RTRIM(p_TEXT)) + 1;
END IF;
RETURN SUBSTR (p_TEXT, v_POS_, v_POS2 - v_POS_);
END;
I did not understand this code carefully, but from the results, the following two pieces of code have the same meaning.
select FUNC_PART('asdfghsdfg', 3, 's')
from dual;
select regexp_substr('asdfghsdfg', '[^s]+', 1, 3)
from dual;
This is likely to be migrated from other databases to the code in oracle, because oracle does not need such a custom function
I'm learning about Oracle Apex, Oracle SQL and PL/SQL and I'm currently learning about functions. I have written a function in which a table is created, data is stored and the table is returned to the calling query. The problem is the code won't compile. I can't see where the problem may be and I've compared the code to various online resources including this site. Everything looks fine to me, so the answer is not obvious to me.
This is the code I wrote:
CREATE OR REPLACE TYPE t_table AS OBJECT
(
futureValues NUMBER
);
CREATE OR REPLACE TYPE t_futureValues AS TABLE OF t_table;
/
CREATE OR REPLACE FUNCTION "CALCULATE_VALUE"( lastRowMinus0 IN NUMBER DEFAULT 1,
lastRowMinus1 IN NUMBER DEFAULT 2,
lastRowMinus2 IN NUMBER DEFAULT 3,
lastRowMinus3 IN NUMBER DEFAULT 4,
lastRowMinus4 IN NUMBER DEFAULT 5,
lastRowMinus5 IN NUMBER DEFAULT 6,
lastRowMinus6 IN NUMBER DEFAULT 7 )
RETURN t_futureValues AS
tableObject t_futureValues;
predictedValue NUMBER := 0;
lastRowMinus0Value NUMBER := 0;
lastRowMinus1Value NUMBER := 0;
lastRowMinus2Value NUMBER := 0;
lastRowMinus3Value NUMBER := 0;
lastRowMinus4Value NUMBER := 0;
lastRowMinus5Value NUMBER := 0;
lastRowMinus6Value NUMBER := 0;
avgDiff NUMBER := 0;
BEGIN
tableObject := t_futureValues();
lastRowMinus0Value := 3;
lastRowMinus1Value := 6;
lastRowMinus2Value := 9;
lastRowMinus3Value := 12;
lastRowMinus4Value := 14;
lastRowMinus5Value := 20;
lastRowMinus6Value := 60;
avgDiff := (lastRowMinus5Value - lastRowMinus6Value) + avgDiff;
avgDiff := (lastRowMinus4Value - lastRowMinus5Value) + avgDiff;
avgDiff := (lastRowMinus3Value - lastRowMinus4Value) + avgDiff;
avgDiff := (lastRowMinus2Value - lastRowMinus3Value) + avgDiff;
avgDiff := (lastRowMinus1Value - lastRowMinus2Value) + avgDiff;
avgDiff := (lastRowMinus0Value - lastRowMinus1Value) + avgDiff;
avgDiff := avgDiff / 6;
predictedValue := avgDiff + lastRowMinus0Value;
begin
for i in 2..13 loop
predictedValue := predictedValue + avgDiff;
IF predictedValue < 0 THEN
predictedValue := 0;
END IF;
insert into tableObject(futureValues)
values(predictedValue);
end loop;
end;
RETURN (tableObject);
END;
The error message I get is:
ORA-06545: PL/SQL: compilation error - compilation aborted ORA-06550: line 6, column 1: PLS-00103: Encountered the symbol "CREATE" ORA-06550: line 0, column 0: PLS-00565: T_TABLE must be completed as a potential REF target (object type)
I have no doubt that the problem is something simple, so if anyone knows, then I'd be grateful.
I don't work with types very often, but your insert is trying to insert into an array. A table must be the target of an insert.
Use the following code:
CREATE OR REPLACE TYPE brianl.t_table AS OBJECT
(
futureValues NUMBER
);
CREATE OR REPLACE TYPE brianl.t_futureValues AS TABLE OF t_table;
/
CREATE OR REPLACE FUNCTION brianl."CALCULATE_VALUE"( lastRowMinus0 IN NUMBER DEFAULT 1,
lastRowMinus1 IN NUMBER DEFAULT 2,
lastRowMinus2 IN NUMBER DEFAULT 3,
lastRowMinus3 IN NUMBER DEFAULT 4,
lastRowMinus4 IN NUMBER DEFAULT 5,
lastRowMinus5 IN NUMBER DEFAULT 6,
lastRowMinus6 IN NUMBER DEFAULT 7 )
RETURN t_futureValues AS
tableObject t_futureValues;
predictedValue NUMBER := 0;
lastRowMinus0Value NUMBER := 0;
lastRowMinus1Value NUMBER := 0;
lastRowMinus2Value NUMBER := 0;
lastRowMinus3Value NUMBER := 0;
lastRowMinus4Value NUMBER := 0;
lastRowMinus5Value NUMBER := 0;
lastRowMinus6Value NUMBER := 0;
avgDiff NUMBER := 0;
BEGIN
tableObject := t_futureValues();
lastRowMinus0Value := 3;
lastRowMinus1Value := 6;
lastRowMinus2Value := 9;
lastRowMinus3Value := 12;
lastRowMinus4Value := 14;
lastRowMinus5Value := 20;
lastRowMinus6Value := 60;
avgDiff := (lastRowMinus5Value - lastRowMinus6Value) + avgDiff;
avgDiff := (lastRowMinus4Value - lastRowMinus5Value) + avgDiff;
avgDiff := (lastRowMinus3Value - lastRowMinus4Value) + avgDiff;
avgDiff := (lastRowMinus2Value - lastRowMinus3Value) + avgDiff;
avgDiff := (lastRowMinus1Value - lastRowMinus2Value) + avgDiff;
avgDiff := (lastRowMinus0Value - lastRowMinus1Value) + avgDiff;
avgDiff := avgDiff / 6;
predictedValue := avgDiff + lastRowMinus0Value;
begin
for i in 2..13 loop
predictedValue := predictedValue + avgDiff;
IF predictedValue < 0 THEN
predictedValue := 0;
END IF;
tableobject.extend();
tableobject(tableobject.count).futureValues := predictedValue;
-- insert into tableObject(futureValues)
-- values(predictedValue);
end loop;
end;
RETURN (tableObject);
END;
I have the following function GET_UN_COLLECTED_4LD which returns the type ld_data_type:
CREATE OR REPLACE TYPE ld_data_type AS OBJECT(collected NUMBER, uncollected NUMBER);
/
CREATE OR REPLACE FUNCTION GET_UN_COLLECTED_4LD (VAPPOINTOFCAID NUMBER,
VPREVLIQUIDATE NUMBER,
VCURRLIQUIDATE NUMBER,
VNEXTLIQUIDATE NUMBER,
YEPT NUMBER)
RETURN LD_DATA_TYPE
AS
OUT_VAR LD_DATA_TYPE;
VNETV23 NUMBER;
VNETV24 NUMBER;
VCURR23 NUMBER;
VCURR24 NUMBER;
VCOLLECTED NUMBER;
VUNCOLLECTED NUMBER;
BEGIN
SELECT SUM (NETX) - SUM (NETP)
INTO VNETV23
FROM VIEW_CUSTOMER_TRN4INVS4LD
WHERE APPOINTOFCAID = VAPPOINTOFCAID AND VAT = ABS (1.23);
SELECT SUM (NETX) - SUM (NETP)
INTO VNETV24
FROM VIEW_CUSTOMER_TRN4INVS4LD
WHERE APPOINTOFCAID = VAPPOINTOFCAID AND VAT = ABS (1.24);
VCOLLECTED := 0;
VUNCOLLECTED := 0;
CASE
WHEN YEPT = 0
THEN
VCURR24 := VCURRLIQUIDATE - VNETV24;
CASE
WHEN VCURR24 > 0
THEN
VCOLLECTED := VNETV24 * 1.24;
VCURR23 := VCURRLIQUIDATE - VNETV23;
CASE
WHEN VCURR23 > 0
THEN
VCOLLECTED := -999;
ELSE
VCOLLECTED :=
VCOLLECTED + ( (VCURRLIQUIDATE - VCURR24) * 1.23);
END CASE;
ELSE
VCOLLECTED := -1999;
END CASE;
ELSE
OUT_VAR.COLLECTED := -888;
OUT_VAR.UNCOLLECTED := -889;
END CASE;
SELECT VCOLLECTED, VUNCOLLECTED
INTO OUT_VAR.COLLECTED, OUT_VAR.UNCOLLECTED
FROM DUAL;
/*
OPEN buffer_cur;
FETCH buffer_cur INTO out_var.val1, out_var.val2;
CLOSE buffer_cur; */
RETURN OUT_VAR;
END GET_UN_COLLECTED_4LD;
When I call the function like
select GET_UN_COLLECTED_4LD(171231, 42240, 31680, 0, 0) from dual;`
I get an error:
Execution (50: 8): ORA-06530: Reference to uninitialized composite
ORA-06512: at "C##SOLSA.GET_UN_COLLECTED_4LD", line 56
I'm use Oracle 12c Standard edition.
How should I be calling the function GET_UN_COLLECTED_4LD and Where is the problem that causes the error?
As the error says, you haven't initialised your object variable:
...
RETURN LD_DATA_TYPE
AS
OUT_VAR LD_DATA_TYPE := new LD_DATA_TYPE(null, null);
...
Your logic is slightly confused though; at the end of your case you do:
ELSE
OUT_VAR.COLLECTED := -888;
OUT_VAR.UNCOLLECTED := -889;
but then overwrite the value immediately afterwards with:
SELECT VCOLLECTED, VUNCOLLECTED
INTO OUT_VAR.COLLECTED, OUT_VAR.UNCOLLECTED
FROM DUAL;
Possibly you meant to set VCOLLECTED and VUNCOLLECTED in that ELSE. If you did that then you wouldn't need to initialise OUT_VAR, as the first remaining reference would create it; which you could do as:
OUT_VAR := LD_DATA_TYPE (VCOLLECTED, VUNCOLLECTED);
instead of selecting from dual; or you could not have the local variable at all and just do:
...
ELSE
VCOLLECTED := -888;
VUNCOLLECTED := -889;
END CASE;
RETURN LD_DATA_TYPE (VCOLLECTED, VUNCOLLECTED);
END GET_UN_COLLECTED_4LD;
First you need to initialize your object type OUT_VAR before you can set its properties like this:
OUT_VAR:= LD_DATA_TYPE(0,0);
See the details here.
This is the procedure to display the Customer Database:
procedure TfrmMain.mnuCustomerClick(Sender: TObject);
var
j: integer;
begin
con := TFDConnection.Create(nil);
query := TFDQuery.Create(con);
con.LoginPrompt := False;
con.Open('DriverID=SQLite;Database=C:\Users\katiee\Documents\Embarcadero\Studio\Projects\ProgramDatabase;');
query.Connection := con;
query.sql.Text := 'SELECT * FROM CustDatabase ORDER BY ID';
query.Open();
query.First;
sgdDatabases.colCount := 9;
sgdDatabases.FixedCols := 0;
for j := 0 to sgdDatabases.rowCount do
sgdDatabases.ColWidths[j] := 100;
sgdDatabases.Cells[0, 0] := 'ID';
sgdDatabases.Cells[1, 0] := 'First Name';
sgdDatabases.Cells[2, 0] := 'Last Name';
sgdDatabases.Cells[3, 0] := 'Address';
sgdDatabases.Cells[4, 0] := 'Town';
sgdDatabases.Cells[5, 0] := 'County';
sgdDatabases.Cells[6, 0] := 'Postcode';
sgdDatabases.Cells[7, 0] := 'Telephone No.';
sgdDatabases.Cells[8, 0] := 'E-Mail';
row := 1;
while not query.EOF do
begin
ID := query.FieldByName('ID').AsString;
firstname := query.FieldByName('First Name').AsString;
lastname := query.FieldByName('Last Name').AsString;
address := query.FieldByName('Address').AsString;
town := query.FieldByName('Town').AsString;
county := query.FieldByName('County').AsString;
postcode := query.FieldByName('Postcode').AsString;
telno := query.FieldByName('TelNo').AsString;
email := query.FieldByName('Email').AsString;
sgdDatabases.Cells[0, row] := ID;
sgdDatabases.Cells[1, row] := firstname;
sgdDatabases.Cells[2, row] := lastname;
sgdDatabases.Cells[3, row] := address;
sgdDatabases.Cells[4, row] := town;
sgdDatabases.Cells[5, row] := county;
sgdDatabases.Cells[6, row] := postcode;
sgdDatabases.Cells[7, row] := telno;
sgdDatabases.Cells[8, row] := email;
sgdDatabases.RowCount := sgdDatabases.RowCount + 1;
row := row + 1;
query.Next;
end;
end;
This is the procedure to display the Employee Database, which is basically identical except "SELECT * FROM EmplDatabase":
procedure TfrmMain.mnuEmployeeClick(Sender: TObject);
var
i: integer;
begin
con := TFDConnection.Create(nil);
query := TFDQuery.Create(con);
con.LoginPrompt := False;
con.Open('DriverID=SQLite;Database=C:\Users\kasio\Documents\Embarcadero\Studio\Projects\ProgramDatabase;');
query.Connection := con;
query.sql.Text := 'SELECT * FROM EmplDatabase ORDER BY ID';
query.Open();
query.First;
sgdDatabases.colCount := 9;
sgdDatabases.FixedCols := 0;
for i := 0 to sgdDatabases.RowCount do
sgdDatabases.ColWidths[i] := 100;
sgdDatabases.Cells[0, 0] := 'ID';
sgdDatabases.Cells[1, 0] := 'First Name';
sgdDatabases.Cells[2, 0] := 'Last Name';
sgdDatabases.Cells[3, 0] := 'Address';
sgdDatabases.Cells[4, 0] := 'Town';
sgdDatabases.Cells[5, 0] := 'County';
sgdDatabases.Cells[6, 0] := 'Postcode';
sgdDatabases.Cells[7, 0] := 'Telephone No.';
sgdDatabases.Cells[8, 0] := 'E-Mail';
row := 1;
while not query.EOF do
begin
ID := query.FieldByName('ID').AsString;
firstname := query.FieldByName('First Name').AsString;
lastname := query.FieldByName('Last Name').AsString;
address := query.FieldByName('Address').AsString;
town := query.FieldByName('Town').AsString;
county := query.FieldByName('County').AsString;
postcode := query.FieldByName('Postcode').AsString;
telno := query.FieldByName('TelNo').AsString;
email := query.FieldByName('Email').AsString;
sgdDatabases.Cells[0, row] := ID;
sgdDatabases.Cells[1, row] := firstname;
sgdDatabases.Cells[2, row] := lastname;
sgdDatabases.Cells[3, row] := address;
sgdDatabases.Cells[4, row] := town;
sgdDatabases.Cells[5, row] := county;
sgdDatabases.Cells[6, row] := postcode;
sgdDatabases.Cells[7, row] := telno;
sgdDatabases.Cells[8, row] := email;
sgdDatabases.RowCount := sgdDatabases.RowCount + 1;
row := row + 1;
query.Next;
end;
end;
When I run the program, I can open either of the databases on the first click, but then if I click again on either of the Customer or Employee buttons or try to change the database, the following error shows: "Project ProjectQuote.exe raised exception class EInvalidGridOperation with message 'Grid index out of range'".
If I delete the line
sgdDatabases.RowCount := sgdDatabases.RowCount + 1;
from the code, it displays both databases, but only shows the first four rows from the database even if there's more.
(I am aware of the uselessly repeated code and no I can't use anything else other than TStringGrid)
This line of your code looks wrong to me:
for j := 0 to sgdDatabases.rowCount do
sgdDatabases.ColWidths[j] := 100;
The [Index] of a StringGrid's ColWidths property is a column number, not a row number, so sgdDatabases.rowCount should have nothing to do with it. If, at the time the above code executes, the number of rows in the grid is greater than the number of columns, you will get an "Index out of range" error when the value of j reaches a value which represents an invalid column number.
In any case, even if that code were valid in that respect , there is an "off by one" error involving sgdDatabases.rowCount. The row numbers are zero-based, so it should be sgdDatabases.rowCount - 1 (assuming you were attempting to refer to a particular row by index, of course).
A more general point is that you can single-step through your code using the IDE's debugger; if you do that, you will see the exception occur when one particular line is executed, and that's the place to start looking for the cause. You should always include the location of the exception in your SO question, because readers should not have to guess this.
Usually, the IDE debugger will find the exception even if you don't single-step, as long as you go to
Tools | Debugger Options | Embarcadero Debuggers | Language Exceptions
in the IDE and check the checkbox Notify on Language Exceptions.
Btw, it would be better if you wrote a general-purpose routine to populate a StringGrid from a Dataset, maybe along the following lines:
procedure TForm1.DatasetToGrid(Dataset : TDataset; Grid : TStringGrid);
var
Col,
Row : Integer;
begin
Grid.RowCount := 1;
Row := 0;
// The following gives the column headers the names of the
// Dataset fields.
for Col := 0 to Dataset.FieldCount - 1 do
Grid.Cells[Col, Row] := Dataset.Fields[Col].FieldName;
Inc(Row);
Dataset.First;
while not Dataset.Eof do begin
for Col := 0 to Dataset.FieldCount - 1 do begin
// Oops! we don't need this Row := Grid.RowCount;
Grid.Cells[Col, Row] := DataSet.Fields[Col].AsString;;
end;
Dataset.Next;
Grid.RowCount := Grid.RowCount + 1;
Inc(Row);
end;
end;
One of the benefits of doing it that way is that all your mistakes are in one place, not duplicated in duplicated code, so if you fix them once, you're done.