SDO_GEOM.SDO_AREA() function - sql

I have this trouble
declare
cursor tab is
select symbol, SDO_GEOM.SDO_AREA(geom, 0.1)
from budynki2
order by 2 desc;
begin
for x in tab loop
dbms_output.put_line(x.symbol || ' ' ||x.geom);
end loop;
end;
Still I get a error that PLS-00302: component 'GEOM' must be declared
I don't know how I can get in to values of second's column in my curosor.
;((

Try to use
declare
cursor tab is
select symbol, SDO_GEOM.SDO_AREA(b.geom, 0.1)
from budynki2 b
order by 2 desc;
begin
for x in tab loop
dbms_output.put_line(x.symbol || ' ' ||x.geom);
end loop;
end;
by aliasing your table budynki2 as b, and prefix your column geom with this alias as b.geom. Assuming you have a column named geom in your table of type SDO_GEOMETRY, you may have another object, in your schema, whose name is geom, and that ambigious definition causes this error.

Still I get a error that PLS-00302: component 'GEOM' must be declared
In your cusor there is no column name GEOM (column still present in table but cursor not able to identify) and that is what Oracle reporting. You just need to alias your SDO_GEOM.SDO_AREA as GEOM and rest should work.
DECLARE
CURSOR TAB
IS
SELECT SYMBOL,
SDO_GEOM.SDO_AREA (GEOM, 0.1) AS GEOM
FROM BUDYNKI2
ORDER BY 2 DESC;
BEGIN
FOR X IN TAB
LOOP
DBMS_OUTPUT.PUT_LINE (X.SYMBOL || ' ' || X.GEOM);
END LOOP;
END;
See Demo:
Table:
SQL> CREATE TABLE cola_markets (
2 mkt_id NUMBER PRIMARY KEY,
3 name VARCHAR2(32),
4 shape SDO_GEOMETRY);
Table created.
SQL> INSERT INTO cola_markets VALUES(
2 1,
3 'cola_a',
4 SDO_GEOMETRY(
5 2003,
6 NULL,
7 NULL,
8 SDO_ELEM_INFO_ARRAY(1,1003,3),
9 SDO_ORDINATE_ARRAY(1,1, 5,7)
10 )
11 );
1 row created.
SQL> INSERT INTO cola_markets VALUES(
2 2,
3 'cola_b',
4 SDO_GEOMETRY(
5 2003,
6 NULL,
7 NULL,
8 SDO_ELEM_INFO_ARRAY(1,1003,1),
9 SDO_ORDINATE_ARRAY(5,1, 8,1, 8,6, 5,7, 5,1)
10 )
11 );
1 row created.
SQL> INSERT INTO cola_markets VALUES(
2 3,
3 'cola_c',
4 SDO_GEOMETRY(
5 2003,
6 NULL,
7 NULL,
8 SDO_ELEM_INFO_ARRAY(1,1003,1),
9 SDO_ORDINATE_ARRAY(3,3, 6,3, 6,5, 4,5, 3,3)
10 )
11 );
1 row created.
SQL> commit;
Block:
Error Simulation:
You need to note that even though my table has column named SHAPE, when i used it in for loop , it produced error. Same as your case.
SQL> DECLARE
2 CURSOR TAB
3 IS
4 SELECT name, SDO_GEOM.SDO_AREA(shape, 0.005)
5 FROM cola_markets
6 ORDER BY 2 DESC;
7 BEGIN
8 FOR X IN TAB
9 LOOP
10 DBMS_OUTPUT.PUT_LINE (X.NAME || ' ' || X.shape);
11 END LOOP;
12 END;
13 /
DBMS_OUTPUT.PUT_LINE (X.NAME || ' ' || X.shape);
*
ERROR at line 10:
ORA-06550: line 10, column 52:
PLS-00302: component 'SHAPE' must be declared
ORA-06550: line 10, column 11:
PL/SQL: Statement ignored
Remedy
SQL> DECLARE
2 CURSOR TAB
3 IS
4 SELECT name,
SDO_GEOM.SDO_AREA(shape, 0.005) AS GEOM --<-Alised the column and problem is resolved
5 FROM cola_markets
6 ORDER BY 2 DESC;
7 BEGIN
8 FOR X IN TAB
9 LOOP
10 DBMS_OUTPUT.PUT_LINE (X.NAME || ' ' || X.GEOM);
11 END LOOP;
12 END;
13 /
cola_a 24
cola_b 16.5
cola_c 5
PL/SQL procedure successfully completed.

Related

How do I insert data from a table to the XML table

When I run this code I didn't get the right data from the standard table
create table COUNTRY_XML(
C_X sys.xmltype);
begin
for cursor in
(select country, continental, population2019 from countries)
loop
insert into country_xml values(
sys.xmltype.createXML(
'<ac_x createdby="Guangzhe">
<country_info>
<Country>mycursor.country</Country>
<Continental>mycursor.continental</Continental>
<Population2019>mycursor.population2019</Population2019>
</country_info>
</ac_x>'));
end loop;
end;
select c.c_x.extract('/').getstringval() from country_xml c
There results are as follow and they are all the same things for each row.
"<ac_x createdby="Guangzhe">
<country_info>
<Country>mycursor.country</Country>
<Continental>mycursor.continental</Continental>
<Population2019>mycursor.population2019</Population2019>
</country_info>
</ac_x>"
You are not doing concatnation properly.
You need to use || (concatanation operator) as following
Table creation
SQL> CREATE TABLE COUNTRY_XML (
2 C_X SYS.XMLTYPE
3 );
Table created.
Solution you need:
SQL>
SQL> begin
2 for mycursor in -- changed the name
3 (select 'INDIA' as country, 'ASIA' as continental, '130B' as population2019 from dual)
4 --(select country, continental, population2019 from countries)
5 loop
6 insert into country_xml values(
7 sys.xmltype.createXML(
8 '<ac_x createdby="Guangzhe">
9 <country_info>
10 <Country>' || mycursor.country || '</Country>
11 <Continental>' || mycursor.continental|| '</Continental>
12 <Population2019>' || mycursor.population2019|| '</Population2019>
13 </country_info>
14 </ac_x>'));
15 end loop;
16 end;
17 /
PL/SQL procedure successfully completed.
Output
SQL> SELECT C.C_X.EXTRACT('/').GETSTRINGVAL()
2 FROM COUNTRY_XML C
3 ;
C.C_X.EXTRACT('/').GETSTRINGVAL()
--------------------------------------------------------------------------------
<ac_x createdby="Guangzhe">
<country_info>
<Country>INDIA</Country>
<Continental>ASIA</Continental>
<Population2019>130B</Population2019>
</country_info>
</ac_x>
SQL>
Cheers!!

How to use 'sysdate' if its a string constant

I extract data from a table, the field is mostly null, but sometimes it's sysdate. However since its from a table, after getting the field its 'sysdate', between single quotes. How can I use it?
I have tried to_date, to_date(to_char()).
I need something that works within
select to_date('sysdate') from dual;
You can use a case expression:
select case
when the_column = 'sysdate' then sysdate
else to_date(the_column)
end as date_value
from the_table;
The only way I know is dynamic SQL. Here's an example:
SQL> create table test (id number, col varchar2(20));
Table created.
SQL> insert into test
2 select 1, '''sysdate''' from dual union all
3 select 2, null from dual;
2 rows created.
SQL> declare
2 l_res test%rowtype;
3 l_str varchar2(200);
4 begin
5 for cur_r in (select id, col from test) loop
6 l_str := 'select ' || cur_r.id ||', '||
7 nvl(replace(cur_r.col, chr(39), null), 'null') || ' from dual';
8 execute immediate l_str into l_res;
9 dbms_output.put_line(l_res.id ||': '|| l_res.col);
10 end loop;
11 end;
12 /
1: 24.06.2019 12:18:39
2:
PL/SQL procedure successfully completed.
SQL>

my table contain data in below format and does not contain any automated primary key [duplicate]

I have column in my database where the values are coming like the following:
3862,3654,3828
In dummy column any no. of comma separated values can come. I tried with following query but it is creating duplicate results.
select regexp_substr(dummy,'[^,]+',1,Level) as dummycol
from (select * from dummy_table)
connect by level <= length(REGEXP_REPLACE(dummy,'[^,]+'))+1
I am not understanding the problem. Can anyone can help?
Works perfectly for me -
SQL> WITH dummy_table AS(
2 SELECT '3862,3654,3828' dummy FROM dual
3 )
4 SELECT trim(regexp_substr(dummy,'[^,]+',1,Level)) AS dummycol
5 FROM dummy_table
6 CONNECT BY level <= LENGTH(REGEXP_REPLACE(dummy,'[^,]+'))+1
7 /
DUMMYCOL
--------------
3862
3654
3828
SQL>
There are many other ways of achieving it. Read Split single comma delimited string into rows.
Update Regarding the duplicates when the column is used instead of a single string value. Saw the use of DBMS_RANDOM in the PRIOR clause to get rid of the cyclic loop here
Try the following,
SQL> WITH dummy_table AS
2 ( SELECT 1 rn, '3862,3654,3828' dummy FROM dual
3 UNION ALL
4 SELECT 2, '1234,5678' dummy FROM dual
5 )
6 SELECT trim(regexp_substr(dummy,'[^,]+',1,Level)) AS dummycol
7 FROM dummy_table
8 CONNECT BY LEVEL <= LENGTH(REGEXP_REPLACE(dummy,'[^,]+'))+1
9 AND prior rn = rn
10 AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL
11 /
DUMMYCOL
--------------
3862
3654
3828
1234
5678
SQL>
Update 2
Another way,
SQL> WITH dummy_table AS
2 ( SELECT 1 rn, '3862,3654,3828' dummy FROM dual
3 UNION ALL
4 SELECT 2, '1234,5678,xyz' dummy FROM dual
5 )
6 SELECT trim(regexp_substr(t.dummy, '[^,]+', 1, levels.column_value)) AS dummycol
7 FROM dummy_table t,
8 TABLE(CAST(MULTISET
9 (SELECT LEVEL
10 FROM dual
11 CONNECT BY LEVEL <= LENGTH (regexp_replace(t.dummy, '[^,]+')) + 1
12 ) AS sys.OdciNumberList)) LEVELS
13 /
DUMMYCOL
--------------
3862
3654
3828
1234
5678
xyz
6 rows selected.
SQL>
Giving a PL/SQL example where parsing over a table with an ID and column name. This will parse and print out each ID and the parsed value which could then be inserted into a new table or used in some other way.
Input
Column_ID Column_Name
123 (3862,3654,3828)
Output
Column_ID Column_Name
123 3862
123 3654
123 3828
PL/SQL Code
declare
table_name1 varchar2(1000);
string_to_parse varchar2(2000); -- assign string to table name
string_length number := 0; -- string length for loop
string_value varchar2(2000); -- string value to store value in
column_id number;
begin
--some table in the format '123' as column_id, '(3862,3654,3828)' as column_name
--remove the parenthesis or other special characters if needed
update some_table t
set t.column_name = regexp_replace(t.column_name,'\(|\)','');
commit;
for i in (
select * from some_table
) loop
column_id := i.column_id; --assign the id of the colors
string_to_parse := i.column_name; -- assign string to be parsed
if string_to_parse is null then
--at this point insert into a new table, or do whatever else you need
dbms_output.put_line(column_id || ' ' || string_value);
else
--String to parse is the comma
string_to_parse := string_to_parse||',';
string_length := length(string_to_parse) - length(replace(string_to_parse,',',''));
-- Loop through string from parameter
for i in 1 .. string_length loop
-- [^,] matches any character except for the ,
select regexp_substr(string_to_parse,'[^,]+',1,i)
into string_value -- stores value into string_value
from dual; -- dual is a dummy table to work around
--at this point insert into a new table, or do whatever else you need
dbms_output.put_line(column_id || ' ' || string_value);
--clear out the string value
string_value := null;
end loop;
end if;
end loop;
end;

Splitting comma separated values in Oracle

I have column in my database where the values are coming like the following:
3862,3654,3828
In dummy column any no. of comma separated values can come. I tried with following query but it is creating duplicate results.
select regexp_substr(dummy,'[^,]+',1,Level) as dummycol
from (select * from dummy_table)
connect by level <= length(REGEXP_REPLACE(dummy,'[^,]+'))+1
I am not understanding the problem. Can anyone can help?
Works perfectly for me -
SQL> WITH dummy_table AS(
2 SELECT '3862,3654,3828' dummy FROM dual
3 )
4 SELECT trim(regexp_substr(dummy,'[^,]+',1,Level)) AS dummycol
5 FROM dummy_table
6 CONNECT BY level <= LENGTH(REGEXP_REPLACE(dummy,'[^,]+'))+1
7 /
DUMMYCOL
--------------
3862
3654
3828
SQL>
There are many other ways of achieving it. Read Split single comma delimited string into rows.
Update Regarding the duplicates when the column is used instead of a single string value. Saw the use of DBMS_RANDOM in the PRIOR clause to get rid of the cyclic loop here
Try the following,
SQL> WITH dummy_table AS
2 ( SELECT 1 rn, '3862,3654,3828' dummy FROM dual
3 UNION ALL
4 SELECT 2, '1234,5678' dummy FROM dual
5 )
6 SELECT trim(regexp_substr(dummy,'[^,]+',1,Level)) AS dummycol
7 FROM dummy_table
8 CONNECT BY LEVEL <= LENGTH(REGEXP_REPLACE(dummy,'[^,]+'))+1
9 AND prior rn = rn
10 AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL
11 /
DUMMYCOL
--------------
3862
3654
3828
1234
5678
SQL>
Update 2
Another way,
SQL> WITH dummy_table AS
2 ( SELECT 1 rn, '3862,3654,3828' dummy FROM dual
3 UNION ALL
4 SELECT 2, '1234,5678,xyz' dummy FROM dual
5 )
6 SELECT trim(regexp_substr(t.dummy, '[^,]+', 1, levels.column_value)) AS dummycol
7 FROM dummy_table t,
8 TABLE(CAST(MULTISET
9 (SELECT LEVEL
10 FROM dual
11 CONNECT BY LEVEL <= LENGTH (regexp_replace(t.dummy, '[^,]+')) + 1
12 ) AS sys.OdciNumberList)) LEVELS
13 /
DUMMYCOL
--------------
3862
3654
3828
1234
5678
xyz
6 rows selected.
SQL>
Giving a PL/SQL example where parsing over a table with an ID and column name. This will parse and print out each ID and the parsed value which could then be inserted into a new table or used in some other way.
Input
Column_ID Column_Name
123 (3862,3654,3828)
Output
Column_ID Column_Name
123 3862
123 3654
123 3828
PL/SQL Code
declare
table_name1 varchar2(1000);
string_to_parse varchar2(2000); -- assign string to table name
string_length number := 0; -- string length for loop
string_value varchar2(2000); -- string value to store value in
column_id number;
begin
--some table in the format '123' as column_id, '(3862,3654,3828)' as column_name
--remove the parenthesis or other special characters if needed
update some_table t
set t.column_name = regexp_replace(t.column_name,'\(|\)','');
commit;
for i in (
select * from some_table
) loop
column_id := i.column_id; --assign the id of the colors
string_to_parse := i.column_name; -- assign string to be parsed
if string_to_parse is null then
--at this point insert into a new table, or do whatever else you need
dbms_output.put_line(column_id || ' ' || string_value);
else
--String to parse is the comma
string_to_parse := string_to_parse||',';
string_length := length(string_to_parse) - length(replace(string_to_parse,',',''));
-- Loop through string from parameter
for i in 1 .. string_length loop
-- [^,] matches any character except for the ,
select regexp_substr(string_to_parse,'[^,]+',1,i)
into string_value -- stores value into string_value
from dual; -- dual is a dummy table to work around
--at this point insert into a new table, or do whatever else you need
dbms_output.put_line(column_id || ' ' || string_value);
--clear out the string value
string_value := null;
end loop;
end if;
end loop;
end;

Oracle SQl Populating a cursor in a procedure from a sql statement saved in a table field

We want to populate a cursor in a procedure that is populated from a select statement in a table.
We created a table named stored_sql_statments with 2 columns, Created_date & Sql_statement.
In that table we will insert a select statement that selects other data from the database based on the clients needs.
Example:
insert into stored_sql_statments
( Created_date , Sql_statement)
values('2/1/2011', 'Select Client_idn , something_neat from cool_table where animal = 'dog' ')
Then in the procedure we have a bunch of code that does what it needs to do, which will never change, but the select statement we have in the cursor changes periodically. We always need to return 2 fields but the rest of the select statement changes.
So now we need to populate the cursor in the procedure with what the select statement coming form the table.
If it was returning only 1 row we have:
declare
x varchar2(600);
rec1 number(10);
rec2 varchar2(15);
begin
execute immediate select Sql_statement into x from stored_sql_statments where created_date = '2/1/2011';
execute immediate x into rec1, rec2;
...
This works, but we don't need it to go into 2 variables we need it to go into a cursor. The real select statement (the above code is just a simple example of what we need to do) is bringing back thousands of records so we need to use a cursor.
Hope this all makes sense
So if anyone knows how to do this, it would be appreciated.
Are you trying to dynamically populate a ref cursor? if so that isn't difficult to do:
set serveroutput on
declare
sql1 varchar2(500);
sql2 varchar2(500);
procedure runProcess(sqlstatement IN varchar2)
AS
refcrs sys_refcursor;
DTE DATE;
LEVELB NUMBER;
BEGIN
dbms_output.put_line(sqlstatement);
open refcrs for
sqlstatement; -- use 'using' to bind those variables
loop
fetch refcrs into DTE, LEVELB;
exit when refcrs%notfound;
dbms_output.put_line(TO_CHAR(DTE,'MMDDYYYY') || '/' || LEVELB);
end loop;
CLOSE REFCRS;
END runProcess;
begin
sql1 := 'select (sysdate - level) a, level b from dual connect by level < 5';
sql2:= 'select (sysdate + level) a, -level b from dual connect by level < 5';
runProcess(SQL1);
runProcess(SQL2);
end ;
/**
select (sysdate - level) a, level b from dual connect by level < 5
02102011/1
02092011/2
02082011/3
02072011/4
select (sysdate + level) a, -level b from dual connect by level < 5
02122011/-1
02132011/-2
02142011/-3
02152011/-4
**/
As you can see, I am dynamically executing two different select statements in the same procedure and outputting their results.
SQL> drop table stack_overflow;
Table dropped.
SQL> create table stack_overflow (created_date date constraint stack_overflow_pk primary key
2 , sql_statement varchar2(4000) not null)
3 /
Table created.
SQL> drop table source_data;
Table dropped.
SQL> create table source_data (vc varchar2(10) null
2 , n number);
Table created.
SQL> insert into source_data values ('a', 100);
1 row created.
SQL> insert into source_data values ('a', 0);
1 row created.
SQL> insert into source_data values ('b', 50);
1 row created.
SQL> insert into source_data values ('c', null);
1 row created.
SQL> insert into stack_overflow values (sysdate - 3/24, 'select vc, sum(n)
2 from source_data
3 group by vc
4 order by vc asc');
1 row created.
SQL> insert into stack_overflow values (sysdate - 2/24 , 'select vc, avg(n)
2 from source_data
3 group by vc
4 order by vc desc');
1 row created.
SQL> insert into stack_overflow values (sysdate - 1/24 , 'select vc, count(*)
2 from source_data
3 group by vc');
1 row created.
SQL> insert into stack_overflow values (sysdate, 'select vc, count(n)
2 from source_data
3 group by vc');
1 row created.
SQL> commit;
Commit complete.
SQL> declare
2 type stack_overflow_type is record (col_1 varchar2(10), col_2 number);
3 type stack_overflow_cur_type is ref cursor return stack_overflow_type;
4 cursor sql_statement_cur is select sql_statement
5 from stack_overflow
6 order by created_date;
7 --
8 function get_cursor_by_date (i_created_date in date) return stack_overflow_cur_type is
9 l_return_cur sys_refcursor; -- stack_overflow_cur_type;
10 l_sql_statement stack_overflow.sql_statement%TYPE;
11 begin
12 select sql_statement into l_sql_statement
13 from stack_overflow
14 where created_date = i_created_date;
15 --
16 open l_return_cur for l_sql_statement;
17 return l_return_cur;
18 end get_cursor_by_date;
19 --
20 procedure process_and_close_cursor (i_cursor in stack_overflow_cur_type) is
21 l_current_rec stack_overflow_type;
22 begin
23 loop
24 fetch i_cursor into l_current_rec;
25 exit when i_cursor%NOTFOUND;
26 dbms_output.put_line('col_1: ' || l_current_rec.col_1
27 || ' col_2: ' || to_number(l_current_rec.col_2));
28 end loop;
29 --
30 close i_cursor;
31 end;
32 --
33 begin
34 for l_row in (select created_date
35 from stack_overflow
36 order by created_date)
37 loop
38 dbms_output.put_line('Processing the SQL statement created on: '
39 || to_char(l_row.created_date, 'YYYY-MM-DD HH24:Mi:SS'));
40 --
41 process_and_close_cursor(get_cursor_by_date(l_row.created_date));
42 --
43 dbms_output.new_line;
44 end loop;
45 end;
46 /
Processing the SQL statement created on: 2011-02-11 10:01:16
col_1: a col_2: 100
col_1: b col_2: 50
col_1: c col_2:
Processing the SQL statement created on: 2011-02-11 11:01:16
col_1: c col_2:
col_1: b col_2: 50
col_1: a col_2: 50
Processing the SQL statement created on: 2011-02-11 12:01:17
col_1: a col_2: 2
col_1: b col_2: 1
col_1: c col_2: 1
Processing the SQL statement created on: 2011-02-11 13:01:17
col_1: a col_2: 2
col_1: b col_2: 1
col_1: c col_2: 0
PL/SQL procedure successfully completed.