Error: inserting data into hana from oracle using dblink - sql

I am trying to insert into hana database from oracle using dblink.I am getting the below error:
ERROR at line 1: ORA-20001: ORA-28500: connection from ORACLE to a
non-Oracle system returned this message: [SAP AG][LIBODBCHDB
SO][HDBODBC] General error;12000 user-defined error: line 2 col 142
(at pos 277): [12000] (range 3) user-defined error exception: no table
change allowed {HY000,NativeErr = 12000} ORA-06512: at
"POP_REMOTE_TABLES", line 58 ORA-06512: at line 1
Below is the code:
CREATE OR REPLACE VIEW VIEW_TEST_DYNAMIC
(
TRANS_OUT
)
AS
select 'insert into test_dynamic#dblink_hana(cust_id,address) values ('||cust_id||','''||address||''')' as trans_out from
(
select 10 cust_id,'9 Help Street, Level 4' address from dual union all
select 11 cust_id,'22 Victoria Street' address from dual union all
select 12 cust_id,'1495 Franklin Str.' address from dual union all
select 13 cust_id,'30 Hasivim St.,Petah-Tikva' address from dual union all
select 14 cust_id,'2 Jakaranda St' address from dual union all
select 15 cust_id,'61, Science Park Rd' address from dual union all
select 16 cust_id,'61, Social park road.' address from dual union all
select 17 cust_id,'Av. Hermanos Escobar 5756' address from dual union all
select 18 cust_id,'Ave. Hermanos Escobar 5756' address from dual union all
select 19 cust_id,'8000 W FLORISSANT Ave.' address from dual union all
select 20 cust_id,'8600 MEMORIAL PKWY SW' address from dual union all
select 21 cust_id,'8200 FLORISSANTMEMORIALWAYABOVE SW' address from dual union all
select 22 cust_id,'8600 MEMORIALFLORISSANT PKWY SW.' address from dual
) t1;
create table test_remote(local_table_name varchar2(50));
insert into test_remote values('VIEW_TEST_DYNAMIC');
procedure:
CREATE OR REPLACE PROCEDURE pop_remote_tables(p_table_name in varchar2 default 'ALL') as
l_cursor sys_refcursor;
l_trans_out varchar2(32000) := NULL;
l_processed_cnt number := 0;
cursor tab_cur is
select upper(local_table_name) local_table_name from test_remote where active_yn='Y' and
upper(local_table_name) = nvl(decode(upper(p_table_name),'ALL',NULL,upper(p_table_name)),upper(local_table_name));
BEGIN
dbms_output.put_line('Started');
for tab_rec in tab_cur
loop
dbms_output.put_line('Started processing:'||tab_rec.local_table_name);
l_processed_cnt := 0;
open l_cursor for 'select trans_out from ' || dbms_assert.sql_object_name(tab_rec.local_table_name);
loop
fetch l_cursor into l_trans_out;
exit when l_cursor%notfound;
execute immediate l_trans_out;
l_processed_cnt := l_processed_cnt + 1;
end loop;
commit;
close l_cursor;
dbms_output.put_line( 'No of records Inserted:' || l_processed_cnt);
end loop;
dbms_output.put_line('Ended');
EXCEPTION
when others then
raise_application_error(-20001, sqlerrm);
END;
/
sho err;
Can someone please help how to resolve this issue?

Related

i get ORA-01722: invalid number error in plsql

i have problem about ora 01722 i have string prols it is like "1501,1701,1901,2001,2501,2601" or "2321,1331,111231,35501" and i want control table x' column x.rol_id include prols or not but i get error in my code. here is part of my code. thanks.
function get_menu_detay_01(pmenu_kod varchar2,
proller varchar2) return sys_refcursor is
v_cr_1 sys_refcursor;
begin
open v_cr_1 for
select distinct mtd.sira_no,
mtd.seviye_1,
mtd.fa_icon_1,
mtd.seviye_2,
mtd.fa_icon_2,
mtd.seviye_3,
mtd.fa_icon_3,
ut.uygulama_tanim_id,
ut.aciklama,
ut.path,
ut.fa_icon,
ut.href,
ut.onclick
from uat.menu_tanim_d mtd
left join uat.uygulama_tanim ut
on ut.uygulama_tanim_id = mtd.uygulama_tanim_id
left join uat.uygulama_yetki uy
on mtd.uygulama_tanim_id = uy.uygulama_tanim_id
where mtd.menu_kod = pmenu_kod
and uy.rol_id in (select regexp_substr(tt.rol, '[^,]+', 1, level)
from (select proller rol
from dual t) tt
connect by regexp_substr(tt.rol, '[^,]+', 1, level) is not null)
order by mtd.sira_no;
return v_cr_1;
end;
If you say the strings you are splitting has separator , then you need to change the regular expression [^,]+ to to include , instead ; or the other way around
I just tried and its working,
WITH tst
AS
(SELECT 1501 rol_id FROM dual
UNION ALL
SELECT 1701 FROM dual
UNION ALL
SELECT 1901 FROM dual
UNION ALL
SELECT 2001 FROM dual
UNION ALL
SELECT 2501 FROM dual
UNION ALL
SELECT 2601 FROM dual
)
SELECT *
FROM tst x
WHERE x.rol_id in (select regexp_substr(tt.rol, '[^,]+', 1, LEVEL)
from (select '1701,1901,2001,2501,2601' rol
from dual t) tt
connect by regexp_substr(tt.rol, '[^,]+', 1, level) is not null);
EDIT: Test with function Please check how you call the function and pass the string in proper format or not
CREATE OR REPLACE FUNCTION get_menu_detay_01(proller VARCHAR2)
RETURN SYS_REFCURSOR
IS
v_cr_1 SYS_REFCURSOR;
BEGIN
OPEN v_cr_1 FOR
SELECT *
FROM ( SELECT 1501 rol_id FROM dual
UNION ALL
SELECT 1701 FROM dual
UNION ALL
SELECT 1901 FROM dual
UNION ALL
SELECT 2001 FROM dual
UNION ALL
SELECT 2501 FROM dual
UNION ALL
SELECT 2601 FROM dual
) x
WHERE x.rol_id IN (SELECT regexp_substr(tt.rol,'[^,)]+',1,LEVEL)
FROM (SELECT proller rol FROM dual t) tt
CONNECT BY regexp_substr(tt.rol,'[^,]+',1,LEVEL) IS NOT NULL);
RETURN v_cr_1;
END get_menu_detay_01;
Test:
set serveroutput on;
DECLARE
lo_ref_cur SYS_REFCURSOR;
lo_number NUMBER;
BEGIN
lo_ref_cur := get_menu_detay_01('1701,1901,2001,2501,2601');
LOOP
FETCH lo_ref_cur INTO lo_number;
EXIT WHEN lo_ref_cur%NOTFOUND;
dbms_output.put_line(lo_number);
END LOOP;
END;
/
Output:
------
1701
1901
2001
2501
2601
PL/SQL procedure successfully completed.

How to tune an Oracle SQL query

The table temp has the columns "word" and "sentence". Below code checks, if the sentence has any words from the word column. If the word exists, the word will be replaced with a URL (contains the word itself and its id). The code works fine for about 1-10 rows. The table has about 50k records. It consumes the whole of the temp space. How can I review and fine-tune the query?
Requirement: There are 50k words and sentence. The requirement is to replace the words in the sentences with a URL (contains the word and its id) if any of the words exist in the word column. While looking for the words, the search has to be case insensitive. Also, we need to retain the same case in the sentence while replacing with the URL.
Create table temp(
id NUMBER,
word VARCHAR2(1000),
Sentence VARCHAR2(2000)
);
insert into temp
SELECT 1,'automation testing', 'automtestingation TeStInG TEST is popular kind of testing' FROM DUAL UNION ALL
SELECT 2,'testing','manual testing' FROM DUAL UNION ALL
select 2,'test', 'test' FROM DUAL UNION ALL
SELECT 3,'manual testing','this is an old method of testing' FROM DUAL UNION ALL
SELECT 4,'punctuation','automation testing,manual testing,punctuation,automanual testing-testing' FROM DUAL UNION ALL
SELECT 5,'B-number analysis','B-number analysis table' FROM DUAL UNION ALL
SELECT 6,'B-number analysis table','testing B-number analysis' FROM DUAL UNION ALL
SELECT 7,'Not Matched','testing testing testing' FROM DUAL
SQL Types:
CREATE TYPE stringlist IS TABLE OF VARCHAR2(4000);
/
CREATE TYPE intlist IS TABLE OF NUMBER(20,0);
/
PLSQL Function
CREATE FUNCTION replace_words(
word_list IN stringlist,
id_list IN intlist,
sentence IN temp.sentence%TYPE
) RETURN temp.sentence%TYPE
IS
p_sentence temp.sentence%TYPE := UPPER( sentence );
p_pos PLS_INTEGER := 1;
p_min_word_index PLS_INTEGER;
p_word_index PLS_INTEGER;
p_start PLS_INTEGER;
p_index PLS_INTEGER;
o_sentence temp.sentence%TYPE;
BEGIN
LOOP
p_min_word_index := NULL;
p_index := NULL;
FOR i IN 1 .. word_list.COUNT LOOP
p_word_index := p_pos;
LOOP
p_word_index := INSTR( p_sentence, word_list(i), p_word_index );
EXIT WHEN p_word_index = 0;
IF ( p_word_index > 1
AND REGEXP_LIKE( SUBSTR( p_sentence, p_word_index - 1, 1 ), '\w' )
)
OR REGEXP_LIKE( SUBSTR( p_sentence, p_word_index + LENGTH( word_list(i) ), 1 ), '\w' )
THEN
p_word_index := p_word_index + 1;
CONTINUE;
END IF;
IF p_min_word_index IS NULL OR p_word_index < p_min_word_index THEN
p_min_word_index := p_word_index;
p_index := i;
END IF;
EXIT;
END LOOP;
END LOOP;
IF p_index IS NULL THEN
o_sentence := o_sentence || SUBSTR( sentence, p_pos );
EXIT;
ELSE
o_sentence := o_sentence
|| SUBSTR( sentence, p_pos, p_min_word_index - p_pos )
|| 'http://localhost/'
|| id_list(p_index)
|| '/<u>'
|| SUBSTR( sentence, p_min_word_index, LENGTH( word_list( p_index ) ) )
|| '</u>';
p_pos := p_min_word_index + LENGTH( word_list( p_index ) );
END IF;
END LOOP;
RETURN o_sentence;
END;
/
MERGE
MERGE INTO temp dst
USING (
WITH lists ( word_list, id_list ) AS (
SELECT CAST(
COLLECT(
UPPER( word )
ORDER BY LENGTH( word ) DESC, UPPER( word ) ASC, ROWNUM
)
AS stringlist
),
CAST(
COLLECT(
id
ORDER BY LENGTH( word ) DESC, UPPER( word ) ASC, ROWNUM
)
AS intlist
)
FROM temp
)
SELECT t.ROWID rid,
replace_words(
word_list,
id_list,
sentence
) AS replaced_sentence
FROM temp t
CROSS JOIN lists
) src
ON ( dst.ROWID = src.RID )
WHEN MATCHED THEN
UPDATE SET sentence = src.replaced_sentence;
I separate words (with ids) from sentences, and I put words in lowercase because you want a case insensitive search anyway. If I find two matches at the same position in the sentence, I choose the longer one. If there are overlaps ('manual testing' and 'testing strategy'), I always choose the "word" that comes first in the sentence.
Best regards,
Stew Ashton
SQL> Create table temp(
2 id NUMBER,
3 word VARCHAR2(1000),
4 Sentence VARCHAR2(2000)
5 );
SQL> insert into temp
2 SELECT 1,'automation testing', 'automtestingation TeStInG TEST is popular kind of testing' FROM DUAL UNION ALL
3 SELECT 2,'testing','manual testing' FROM DUAL UNION ALL
4 select 2,'test', 'test' FROM DUAL UNION ALL
5 SELECT 3,'manual testing','this is an old method of testing' FROM DUAL UNION ALL
6 SELECT 4,'punctuation','automation Testing,manual tEsting,punctuation,automanual teSting-tesTing' FROM DUAL UNION ALL
7 SELECT 5,'B-number analysis','B-number analysis table' FROM DUAL UNION ALL
8 SELECT 6,'B-number analysis table','testing B-number analysis' FROM DUAL UNION ALL
9 SELECT 7,'Not Matched','Testing tEsting teSting' FROM DUAL;
SQL> create table sentences as select sentence from temp;
SQL> create table words cache as
2 select length(word) word_length,
3 min(id) id,
4 lower(word) word
5 from temp
6 group by length(word), lower(word);
SQL> insert into sentences
2 select listagg(word, ',') within group(order by word)
3 from words;
SQL> insert into sentences values('Nothing matches here');
SQL> commit;
SQL> declare
2 cursor cur_sentences is
3 select rowid rid, sentence from sentences s
4 where exists (
5 select null from words
6 where instr(lower(s.sentence), word) > 0
7 )
8 for update;
9 type tt_sentences is table of cur_sentences%rowtype;
10 lt_sentences tt_sentences;
11 lt_sentences_new tt_sentences;
12
13 function change_sentence(p_sentence in sentences.sentence%type)
14 return sentences.sentence%type is
15 cursor cur_words(cp_sentence in sentences.sentence%type) is
16 with recurse (pos, word_length, id, word) as (
17 select regexp_instr(cp_sentence, '(^|\W)('||word||')(\W|$)', 1, 1, 0, 'i', 2),
18 word_length, id, word
19 from words
20 where regexp_instr(cp_sentence, '(^|\W)('||word||')(\W|$)', 1, 1, 0, 'i', 2) > 0
21 union all
22 select regexp_instr(cp_sentence, '(^|\W)('||word||')(\W|$)', pos+1, 1, 0, 'i', 2),
23 word_length, id, word
24 from recurse
25 where regexp_instr(cp_sentence, '(^|\W)('||word||')(\W|$)', pos+1, 1, 0, 'i', 2) > 0
26 )
27 select pos, word_length, id, word,
28 substr(cp_sentence, pos, length(word)) new_word
29 from recurse
30 order by pos, word_length desc;
31 type tt_words is table of cur_words%rowtype;
32 lt_words tt_words;
33 lt_words_kept tt_words:= new tt_words();
34 l_pos number := 0;
35 l_sentence sentences.sentence%type := p_sentence;
36 begin
37 open cur_words(p_sentence);
38 fetch cur_words bulk collect into lt_words;
39 for i in 1..lt_words.count loop
40 if l_pos < lt_words(i).pos then
41 l_pos := lt_words(i).pos + lt_words(i).word_length;
42 lt_words_kept.extend;
43 lt_words_kept(lt_words_kept.count) := lt_words(i);
44 end if;
45 end loop;
46 close cur_words;
47 for i in reverse 1..lt_words_kept.count loop
48 l_sentence := regexp_replace(
49 l_sentence,
50 lt_words_kept(i).new_word,
51 'http://localhost/'||lt_words_kept(i).id||'/<u>'||lt_words_kept(i).new_word||'</u>',
52 lt_words_kept(i).pos,
53 1
54 );
55 end loop;
56 return l_sentence;
57 exception when others then
58 close cur_words;
59 raise;
60 end change_sentence;
61
62 begin
63 open cur_sentences;
64 loop
65 fetch cur_sentences bulk collect into lt_sentences limit 100;
66 exit when lt_sentences.count = 0;
67 lt_sentences_new := new tt_sentences();
68 lt_sentences_new.extend(lt_sentences.count);
69 for i in 1..lt_sentences.count loop
70 lt_sentences_new(i).sentence := change_sentence(lt_sentences(i).sentence);
71 end loop;
72 forall i in 1..lt_sentences.count
73 update sentences set sentence = lt_sentences_new(i).sentence where rowid = lt_sentences(i).rid;
74 exit when cur_sentences%notfound;
75 end loop;
76 close cur_sentences;
77 exception when others then
78 if cur_sentences%isopen then
79 close cur_sentences;
80 raise;
81 end if;
82 end;
83 /
PL/SQL procedure successfully completed.
SQL> select * from sentences order by 1;
SENTENCE
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Nothing matches here
automtestingation http://localhost/2/<u>TeStInG</u> http://localhost/2/<u>TEST</u> is popular kind of http://localhost/2/<u>testing</u>
http://localhost/1/<u>automation Testing</u>,http://localhost/3/<u>manual tEsting</u>,http://localhost/4/<u>punctuation</u>,automanual http://localhost/2/<u>teSting</u>-http://localhost/2/<u>tesTing</u>
http://localhost/1/<u>automation testing</u>,http://localhost/5/<u>b-number analysis</u>,http://localhost/6/<u>b-number analysis table</u>,http://localhost/3/<u>manual testing</u>,http://localhost/7/<u>not matched</u>,http://localhost/4/<u>punctuation</u>,http://localhost/2/<u>test</u>,http://localhost/2/<u>testing</u>
http://localhost/2/<u>Testing</u> http://localhost/2/<u>tEsting</u> http://localhost/2/<u>teSting</u>
http://localhost/2/<u>test</u>
http://localhost/2/<u>testing</u> http://localhost/5/<u>B-number analysis</u>
http://localhost/3/<u>manual testing</u>
http://localhost/6/<u>B-number analysis table</u>
this is an old method of http://localhost/2/<u>testing</u>

dynamic columns in oracle using sql

I have following example of table. Thera can be unlimited branch and customers. I need group this branches and count their customers, then show it's with different columns.
BRANCHNAME CUSTOMERNO
100 1001010
100 1001011
103 1001012
104 1001013
104 1001014
104 1001015
105 1001016
105 1001017
106 1001018
Note that there can be unlimited branch and customers, the query must work not only this case.
In this case the accepted result is:
100 103 104 105 106
2 1 3 2 1
Example SQL DATA
select '100' BranchName,'1001010' CustomerNo from dual UNION ALL
select '100' BranchName,'1001011' CustomerNo from dual UNION ALL
select '103' BranchName,'1001012' CustomerNo from dual UNION ALL
select '104' BranchName,'1001013' CustomerNo from dual UNION ALL
select '104' BranchName,'1001014' CustomerNo from dual UNION ALL
select '104' BranchName,'1001015' CustomerNo from dual UNION ALL
select '105' BranchName,'1001016' CustomerNo from dual UNION ALL
select '105' BranchName,'1001017' CustomerNo from dual UNION ALL
select '106' BranchName,'1001018' CustomerNo from dual
I think it is possible, though quite complicated, to write a pipelined table function that returns a variable structure. Your pipeline table function will use the Oracle Data Cartridge interface and the magic of the AnyDataSet type to return a dynamic structure at runtime. You can then use that in subsequent SQL statements as if it was a table, i.e.
SELECT *
FROM TABLE( your_pipelined_function( p_1, p_2 ));
A couple more references that discuss the same sample implementation
Dynamic SQL Pivoting
The Implementing the Interface Approach section of the Oracle Data Cartridge Developer's Guide
Method4. After downloading and installing the open source PL/SQL code, here is a complete implementation:
--Create sample table.
create table branch_data as
select '100' BranchName,'1001010' CustomerNo from dual UNION ALL
select '100' BranchName,'1001011' CustomerNo from dual UNION ALL
select '103' BranchName,'1001012' CustomerNo from dual UNION ALL
select '104' BranchName,'1001013' CustomerNo from dual UNION ALL
select '104' BranchName,'1001014' CustomerNo from dual UNION ALL
select '104' BranchName,'1001015' CustomerNo from dual UNION ALL
select '105' BranchName,'1001016' CustomerNo from dual UNION ALL
select '105' BranchName,'1001017' CustomerNo from dual UNION ALL
select '106' BranchName,'1001018' CustomerNo from dual;
--Create a dynamic pivot in SQL.
select *
from table(method4.dynamic_query(
q'[
--Create a select statement
select
--The SELECT:
'select'||chr(10)||
--The column list:
listagg(
replace(q'!sum(case when BranchName = '#BRANCH_NAME#' then 1 else 0 end) "#BRANCH_NAME#"!', '#BRANCH_NAME#', BranchName)
, ','||chr(10)) within group (order by BranchName)||chr(10)||
--The FROM:
'from branch_data' v_sql
from
(
--Distinct BranchNames.
select distinct BranchName
from branch_data
)
]'
));
If you just want to report the results somewhere, you may use a cursor for the select statement:
select branchname, count(*) from test group by branchname order by branchname asc;
Looping through the cursor you may get your values.
here is my sample:
declare
v_b varchar2(1000);
v_t varchar2(1000);
begin
for i in (select branchname, count(*) total from test group by branchname order by branchname asc)
loop
v_b := v_b || i.branchname || ' ';
v_t := v_t || i.total || ' ';
end loop;
dbms_output.put_line(v_b);
dbms_output.put_line(v_t);
end;
This will get it in rows (rather than columns):
SELECT branchname,
COUNT( DISTINCT customerno ) AS customers
FROM your_table
GROUP BY branchname;
(Note: you can omit the DISTINCT keyword if there will never be repeats of the branchname, customerno pair.)
Without knowing what the branch names are you are could only do a dynamic pivot.
It would be much simpler to take the output of the above query (in row format) and transpose it in whatever front-end you are using to access the database.
From comments:
I need a report in this format, and don't want write some application , wants to do with sql for easily export to excell in such format
No, you don't need it in column format in SQL. You can put it into excel in row format and then use excel's TRANSPOSE function to convert it (very simply) to columns without having to implement a complicated dynamic SQL solution.
What about this solution. Without no table creation, just set the v_sql parameter.
SET SERVEROUTPUT ON SIZE 100000
DECLARE
v_cursor sys_refcursor;
CURSOR get_columns
IS
SELECT EXTRACTVALUE (t2.COLUMN_VALUE, 'node()') VALUE
FROM (SELECT *
FROM TABLE (XMLSEQUENCE (v_cursor))) t1,
TABLE (XMLSEQUENCE (EXTRACT (t1.COLUMN_VALUE, '/ROW/node()'))) t2;
v_column VARCHAR2 (1000);
v_value VARCHAR2 (1000);
v_counter NUMBER (3) := 0;
v_sql VARCHAR2 (4000);
BEGIN
v_sql :=
'SELECT branchname, COUNT (DISTINCT customerno) AS customers'
|| ' FROM (SELECT 100 branchname, 1001010 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 100 branchname, 1001011 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 103 branchname, 1001012 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 104 branchname, 1001013 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 104 branchname, 1001014 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 104 branchname, 1001015 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 105 branchname, 1001016 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 105 branchname, 1001017 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 106 branchname, 1001018 customerno'
|| ' FROM DUAL)'
|| ' GROUP BY branchname';
OPEN v_cursor FOR v_sql;
FOR v_record IN get_columns
LOOP
IF v_counter = 0
THEN
v_column := v_column || v_record.VALUE || ' ';
v_counter := 1;
ELSIF v_counter = 1
THEN
v_value := v_value || v_record.VALUE || ' ';
v_counter := 0;
END IF;
END LOOP;
DBMS_OUTPUT.put_line (v_column);
DBMS_OUTPUT.put_line (v_value);
END;
/
And the output is
100 105 104 103 106
2 2 3 1 1
with src as
(select '100' BranchName,'1001010' CustomerNo from dual UNION ALL
select '100' BranchName,'1001011' CustomerNo from dual UNION ALL
select '103' BranchName,'1001012' CustomerNo from dual UNION ALL
select '104' BranchName,'1001013' CustomerNo from dual UNION ALL
select '104' BranchName,'1001014' CustomerNo from dual UNION ALL
select '104' BranchName,'1001015' CustomerNo from dual UNION ALL
select '105' BranchName,'1001016' CustomerNo from dual UNION ALL
select '105' BranchName,'1001017' CustomerNo from dual UNION ALL
select '106' BranchName,'1001018' CustomerNo from dual )
SELECT * FROM
(select BranchName from src)
PIVOT XML
(COUNT(*) FOR (BranchName)
IN
(SELECT DISTINCT BranchName FROM SRC))
This query gives the output in xml format. The whole xml data will be contained in the field that the query results(The query has only single row-sinlge column output). The next step is to parse the xml data and display it in tabular form.
You can use this selection:
SELECT branchname, count(*)
FROM test
GROUP BY branchname
In general it is not professional to use selection for every number in branchname.

ORA-01790 datatype: how to add the ability to use the text in the name, and not just numbers

I've got next code that I need to understand and make some changes.
To be more specific is the next challenge:
I need to give the possibility to choose not only the number, but the string for the name of the some panel.
Instead of this:
select -1 as num from dual union all
I should do this(name must contain text instead of number in this case)
select 'some_text' as num from dual union all
When I make this change, an error occurs as follows:
PL/SQL: ORA-01790: expression must have same datatype as corresponding
expression
Here is a code
REQUEST_SCRIPT:
declare
l_data clob := request_pkg.get_request_data('panel_rza');
l_panel constant varchar2(2000) := tpl_pkg.get_block(l_data, 'panel');
l_panels clob;
l_count integer := 0;
begin
l_panels := '
';
for c in(
select 9 as num from dual union all
select -1 as num from dual union all
select 2 as num from dual union all
select 4 as num from dual union all
select 19 as num from dual union all
select 23 as num from dual union all
select 18 as num from dual union all
select 22 as num from dual union all
select 8 as num from dual union all
select -3 as num from dual union all
select 20 as num from dual union all
select -2 as num from dual union all
select 24 as num from dual
) loop
dbms_lob.append(l_panels, replace(l_panel, '{num}', c.num));
select count(*)
into l_count
from dual
where exists(
select *
from v_scheme_element_panel
where upper(fk_table_name) = upper('panel_rza_' || c.num)
and upper(type) = 'BLINKER'
and upper(value) = 'ON'
);
if(l_count = 1) then
tpl_pkg.set_block(l_panels, 'active', tpl_pkg.get_block(l_panel, 'active'));
tpl_pkg.clear_block(l_panels, 'inactive');
else
select count(*)
into l_count
from dual
where exists(
select *
from v_scheme_element_panel
where upper(fk_table_name) = upper('panel_rza_' || c.num)
and upper(type) = 'BLINKER'
and upper(value) = 'CLOSED'
);
if(l_count = 1) then
tpl_pkg.set_block(l_panels, 'inactive', tpl_pkg.get_block(l_panel, 'inactive'));
tpl_pkg.clear_block(l_panels, 'active');
else
tpl_pkg.clear_block(l_panels, 'active');
tpl_pkg.clear_block(l_panels, 'inactive');
end if;
end if;
end loop;
:result := '<dialog id="dialog_panel_rza"><title>Выбор Панелей РЗА</title><text><![CDATA[';
dbms_lob.append(:result, l_data);
tpl_pkg.set_block(:result, 'panel', l_panels);
dbms_lob.append(:result, ']]></text></dialog>');
end;
REQUEST_CODE:
<table>
<!-- BEGIN panel -->
<tr>
<td>
Панель управления РЗА № {num}
</td>
<td>
<td align="right">
<!-- BEGIN active --><img height="24" src="./images/panel/panel_rza_alarm.png"><!-- END active -->
<!-- BEGIN inactive --><img height="24" src="./images/panel/panel_rza_inactive.png"><!-- END inactive -->
</td>
</tr>
<!-- END panel -->
</table>
TPL_PKG:
function get_block(
p_text clob,
p_block_name varchar2
) return clob
is
l_block_text clob;
begin
l_block_text := regexp_substr(p_text, '<!-- BEGIN '||p_block_name||' -->.*<!-- END '||p_block_name||' -->',1,1,'inm');
l_block_text := replace(l_block_text, '<!-- BEGIN '||p_block_name||' -->');
l_block_text := replace(l_block_text, '<!-- END '||p_block_name||' -->');
return l_block_text;
end;
Thanks
You should use to_char when you have varying datatypes.
select to_char(1) from dual
union all
select 'abc' from dual
If you wish to mix strings and numbers you have to explicitly convert the numbers into strings, i.e.:
select to_char(9) as num from dual union all
select to_char(-1) as num from dual union all
select to_char(2) as num from dual union all
select 'some_text' as num from dual union all

how to write loop in pl/sql that goes over numbers

I want to write a loop that iterates over numbers 105 102 19 17 101 16 106 107
for each iteration I want to plug the number in a query and insert it into a table.
pseudo:
LOOP (105 102 19 17 101 16 106 107)
FETCH select * from some_table where value=current_iteration_index --105..etc.
INTO my_rec_type
END LOOP;
Another method:
declare
type numListType is table of number;
numList numListType;
begin
numList := numListType(
105,102,19,17,101,16,106,107
);
for i in numList.FIRST..numList.LAST loop
-- your usage of element goes here
dbms_output.put_line(numList(i));
end loop;
end;
/
Here's a more concise, albeit no less ugly, alternative:
DECLARE
CURSOR C IS
SELECT val
FROM (SELECT LEVEL val FROM dual CONNECT BY LEVEL < 1000)
WHERE val IN (105,102,19,17,101,16,106,107);
BEGIN
FOR R IN C LOOP
select *
INTO my_rec_type
from some_table
where value=R.val; --105..etc.
... more stuff
END LOOP;
END;
The advantage here (IMO) is you only need to modify the IN list and perhaps the limit on the CONNECT BY clause to change your results.
While there are a couple of solutions to your questions, but based on your handle I'm going to tell you that I think you're approaching this the wrong way - you're not taking advantage of the features of the database.
Can you explain why
select * from some_table where value in (105, 102, 19, 17, 101, 16, 106, 107)
doesn't do what you want it to do?
Here's an option, using a Cursor FOR LOOP, and the %ROWTYPE attribute:
DECLARE
my_rec_type SOME_TABLE%ROWTYPE;
CURSOR c IS
SELECT 105 AS c_index FROM DUAL
UNION ALL
SELECT 102 AS c_index FROM DUAL
UNION ALL
SELECT 19 AS c_index FROM DUAL
UNION ALL
SELECT 17 AS c_index FROM DUAL
UNION ALL
SELECT 101 AS c_index FROM DUAL
UNION ALL
SELECT 16 AS c_index FROM DUAL
UNION ALL
SELECT 106 AS c_index FROM DUAL
UNION ALL
SELECT 107 AS c_index FROM DUAL
BEGIN
FOR cursor_rec IN c
LOOP
SELECT *
INTO my_rec_type
FROM some_table
WHERE value = cursor_rec.c_index;
END LOOP;
END;