Is it practically possible to create a triangle of stars like this as below in PL/SQL. I know that this could be done easily in any other programming language like C,C++,Java but want to know whether it is really possible with just SQL or PL/SQL. This is for my homework and I should use conditional clauses (IF THEN ELSE), loops(FOR, WHILE).
*
***
*****
*******
*********
***********
*************
and
*****
***
*
Try this.
The first loop will print the stars in triangle and the second loop will reverse it.
In PL/SQL:
BEGIN
FOR i IN 1 .. :p
LOOP
DBMS_OUTPUT.put_line (LPAD (LPAD ('*', i, '*'), :p + 1, ' '));
END LOOP;
FOR i IN 1 .. :p
LOOP
DBMS_OUTPUT.put_line (LPAD (LPAD ('*', :p-i, '*'), :p + 1, ' '));
END LOOP;
END;
In SQL:
SELECT LPAD (LPAD ('*', level, '*'), :p + 1, ' ') a
FROM DUAL
CONNECT BY LEVEL <= :p;
This can be done purely in sql (in Oracle), like so:
SELECT RPAD(' ', :p_num_triangle_rows - LEVEL) || RPAD('*', LEVEL * 2 -1, '*') || RPAD(' ', :p_num_triangle_rows - LEVEL) triangle
FROM dual
CONNECT BY LEVEL <= :p_num_triangle_rows
ORDER BY CASE WHEN :p_ascending_or_descending = 'a' THEN LEVEL END ASC,
CASE WHEN :p_ascending_or_descending = 'd' THEN LEVEL END DESC;
p_num_triangle_rows := 20, p_ascending_or_desc := 'a':
TRIANGLE
--------------------------------------------------------------------------------
*
***
*****
*******
*********
***********
*************
***************
*****************
*******************
*********************
***********************
*************************
***************************
*****************************
*******************************
*********************************
***********************************
*************************************
***************************************
p_num_triangle_rows := 3, p_ascending_or_desc := 'd':
TRIANGLE
--------------------------------------------------------------------------------
*****
***
*
ETA: Here is a PL/SQL version that will do what you're after:
DECLARE
PROCEDURE produce_triangle_rows (p_num_triangle_rows IN NUMBER,
p_ascending_or_descending IN VARCHAR2 DEFAULT 'a')
IS
BEGIN
dbms_output.put_line('p_num_triangle_rows = '|| p_num_triangle_rows ||', p_ascending_or_descending = ' || p_ascending_or_descending);
FOR i IN 1..p_num_triangle_rows
LOOP
CASE WHEN p_ascending_or_descending = 'a' THEN
dbms_output.put_line(RPAD(' ', p_num_triangle_rows - i) || RPAD('*', i * 2 - 1, '*') || RPAD(' ', p_num_triangle_rows - i));
WHEN p_ascending_or_descending = 'd' THEN
dbms_output.put_line(RPAD(' ', i - 1) || RPAD('*', 2 * (p_num_triangle_rows - i) + 1, '*') || RPAD(' ', i - 1));
END CASE;
END LOOP;
END produce_triangle_rows;
BEGIN
produce_triangle_rows(p_num_triangle_rows => 5,
p_ascending_or_descending => 'a');
produce_triangle_rows(p_num_triangle_rows => 3,
p_ascending_or_descending => 'd');
END;
/
p_num_triangle_rows = 5, p_ascending_or_descending = a
*
***
*****
*******
*********
p_num_triangle_rows = 3, p_ascending_or_descending = d
*****
***
*
Note that I've wrapped the procedure in an anonymous block purely so I could call it with different parameters. You would just create the produce_triangle_rows procedure on its own and then call it appropriately.
Try this
declare #count int,#num int,#num1 int, #space int, #str varchar(50)
set #count = 3 set #num = 1
while(#num<=#count)
begin
set #num1 = 0 set #space = #count-#num
while (#num1<#num)
begin
if #str is null
set #str = '* '
else
set #str = #str+'* ' set #num1 = #num1+1
end
print (space(#space)+#str)
set #num = #num+1 set #str = null
end
Or
Declare #x varchar(20)=0,#y varchar(20)=5
while(#y>0)
begin
print space(#y)+replicate('*',#x)+replicate('*',#x+1)
set #y=#y-1
set #x=#x+1
end
I found the problem fun, so I solved it in PostgreSQL. Unfortunately repeating characters seems not really be a standardized feature. Here are the syntax to use for the most common RDBMSes:
PostgreSQL : repeat('*', n)
Oracle : rpad('', n, '*')
MS SQL Server : replicate('*', n)
MySQL : repeat('*', n)
First create some table with numbers up to whatever is the biggest triangle you can imagine:
create table n10 (n) as
select 0 union
select 1 union
select 2 union
select 3 union
select 4 union
select 5 union
select 6 union
select 7 union
select 8 union
select 9;
create table n1000 (n) as
select 100 * a1.n + 10 * a2.n + a3.n
from n10 a1 cross join n10 a2 cross join n10 a3;
Then to make a triangle of size 5 (replace 5 by any number between 0 and 1000 you want):
with s (s) as (select 5)
select
repeat(' ', s - n - 1) ||
repeat('*', 2 * n + 1) ||
repeat(' ', s - n - 1)
from n1000 cross join s
where n < s
order by n;
with s (s) as (select 5)
select
repeat(' ', s - n - 1) ||
repeat('*', 2 * n + 1) ||
repeat(' ', s - n - 1)
from n1000 cross join s
where n < s
order by n desc;
Related
I have below Two Strings
Src Id = 1:2:3:4
Src Qty = 2:4:7:9
So I want to Insert into a Table like
Insert into tbl (Src_id,qty) values (1,2);
Insert into tbl (Src_id,qty) values (2,4);
Insert into tbl (Src_id,qty) values (3,7);
and so on for all
So How i can use a loop by using APEX_UTIL.STRING_TO_TABLE or something else to align the Src id and Qty to insert them as single row in a table
You don't need a loop (i.e. PL/SQL); everything can be done in SQL. Here's how:
SQL> with test (src_id, src_qty) as
2 (select '1:2:3:4', '2:4:7:9' from dual)
3 select regexp_substr(src_id, '[^:]+', 1, level) ||','||
4 regexp_substr(src_qty, '[^:]+', 1, level) result
5 from test
6 connect by level <= regexp_count(src_id, ':') + 1;
RESULT
---------------------------------------------------------
1,2
2,4
3,7
4,9
SQL>
I have done the Solution as below
DECLARE
l_src_arr2 APEX_APPLICATION_GLOBAL.VC_ARR2;
l_qty_arr2 APEX_APPLICATION_GLOBAL.VC_ARR2;
BEGIN
l_src_arr2 := APEX_UTIL.STRING_TO_TABLE ('1:2:3:4');
l_qty_arr2 := APEX_UTIL.STRING_TO_TABLE ('2:4:7:9');
FOR i IN 1 .. l_src_arr2.COUNT LOOP
DBMS_OUTPUT.PUT_LINE ('Src = ' || l_src_arr2 (i) || ' qty = ' || l_qty_arr2 (i));
END LOOP;
END;
Declare
Vquery varchar2(32000);
Vitem varchar2(50);
Vskuloc varchar2(50);
vstartdate Date;
Vdur Number;
vtype Number;
vqty Float(126);
GP_ohpost Date:= fnc_ohpost;
sdate1 Date:= to_date('01/01/1970','dd/mm/yyyy');
Cursor C_DRIVER is
(Select h.*,b.item,b.skuloc,h.rowid
FROM SCPOMGR.histwide h, SCPOMGR.dfutosku b
WHERE h.dmdunit=b.dmdunit
AND h.loc=b.dfuloc
AND (b.eff = Sdate1 OR b.eff <= h.startdate
AND b.disc = Sdate1 OR b.disc > h.startdate)
And NOT EXISTS (SELECT 1 FROM SCPOMGR.SKUHIST d
WHERE b.dmdunit = d.item
AND b.skuloc = d.loc
AND h.startdate = d.startdate
)) order by h.StartDate;
TYPE GP_cursor_Type IS TABLE OF C_DRIVER%ROWTYPE;
GP_cursor_tab GP_cursor_Type := GP_cursor_type();
c_limit constant PLS_INTEGER DEFAULT 10;
TYPE GP_Insert_type IS TABLE OF scpomgr.skuhist%ROWTYPE;
GP_Insert_tab GP_Insert_type := GP_Insert_type();
GP_tot_accept_fetched NUMBER := 0;
begin
OPEN C_DRIVER;
LOOP
FETCH c_driver BULK COLLECT INTO GP_cursor_tab limit c_limit;
Exit when c_driver%NOTFOUND;
FOR i IN GP_cursor_tab.FIRST .. GP_cursor_tab.LAST LOOP
vquery:= 'Select ...<skipped to make post shortest>';
Execute immediate vquery BULK COLLECT INTO GP_Insert_tab;
FORALL i IN INDICES OF GP_Insert_tab
Insert into scpomgr.skuhist
values( GP_Insert_tab(i).startdate
,1
,10080
,GP_Insert_tab(i).qty
,GP_Insert_tab(i).item
,GP_Insert_tab(i).loc
);
End Loop;
End Loop;
Close C_DRIVER;
END;
/
What i want to do here is i want to use the forall query outside of loop but if i am using the forall with the 2 nd array outside the loop then.all of the records are not getting inserted to the final table..please suggest me some solution....
Ankita.
I didn't know the structure of your tables, so i made a simple tables to understand what should work here:
create table histwide (f1 number);
insert into histwide values (1);
insert into histwide values (2);
create table skuhist (f1 number);
select * from histwide
select * from skuhist
Now i changed your code keeping changed code in comments. Seems it works. I think the trouble was because of you are used Exit when c_driver%NOTFOUND; in begining of loop. It is wrong for FORALL because after first fetching cursor is empty (if limit is reached).
So, my solution of your case:
Declare
Vquery varchar2(32000);
Vitem varchar2(50);
Vskuloc varchar2(50);
vstartdate Date;
Vdur Number;
vtype Number;
vqty Float(126);
GP_ohpost Date:= trunc(sysdate); --fnc_ohpost;
sdate1 Date:= to_date('01/01/1970','dd/mm/yyyy');
Cursor C_DRIVER is
(Select h.*--,b.item,b.skuloc,h.rowid
--FROM SCPOMGR.histwide h, SCPOMGR.dfutosku b
FROM histwide h
/*WHERE h.dmdunit=b.dmdunit
AND h.loc=b.dfuloc
AND (b.eff = Sdate1 OR b.eff <= h.startdate
AND b.disc = Sdate1 OR b.disc > h.startdate)
And NOT EXISTS (SELECT 1 FROM SCPOMGR.SKUHIST d
WHERE b.dmdunit = d.item
AND b.skuloc = d.loc
AND h.startdate = d.startdate
)) order by h.StartDate*/
);
TYPE GP_cursor_Type IS TABLE OF C_DRIVER%ROWTYPE;
GP_cursor_tab GP_cursor_Type := GP_cursor_type();
c_limit constant PLS_INTEGER DEFAULT 10;
TYPE GP_Insert_type IS TABLE OF skuhist%ROWTYPE; --scpomgr.skuhist%ROWTYPE;
GP_Insert_tab GP_Insert_type := GP_Insert_type();
GP_tot_accept_fetched NUMBER := 0;
begin
OPEN C_DRIVER;
LOOP
FETCH c_driver BULK COLLECT INTO GP_cursor_tab limit c_limit;
Exit when GP_cursor_tab.count = 0;
dbms_output.put_line('arr cur size: '||GP_cursor_tab.count);
FOR i IN GP_cursor_tab.FIRST .. GP_cursor_tab.LAST LOOP
vquery:= 'Select * from histwide';
Execute immediate vquery BULK COLLECT INTO GP_Insert_tab;
dbms_output.put_line('arr size: '||GP_Insert_tab.count);
-- FORALL j IN INDICES OF GP_Insert_tab
FORALL j in GP_Insert_tab.first..GP_Insert_tab.last --works too
Insert into skuhist --scpomgr.skuhist
values(GP_Insert_tab(j).f1
/*GP_Insert_tab(i).startdate
,1
,10080
,GP_Insert_tab(i).qty
,GP_Insert_tab(i).item
,GP_Insert_tab(i).loc*/
);
End Loop;
Exit when c_driver%NOTFOUND; --it should be at end of the loop.
End Loop;
Close C_DRIVER;
END;
/
Hope it will help you
good morning guys i have a problem with code i work on Health Care and complain code must be checkbox but they ask for Report that contain the treatment code which is gonna appear in database like this 1:15:2:3 etc so i need to calculate each code separate
i have to count until i get ":" then i need to take the number which can be 1 or 2 digit then making inner join with the other table
can anyone help me to fix this function and the problem in the loop and get the number for each one
create or replace function hcc_get_tcd_codes (p_id in number )
return varchar2 is
x number := 0 ;
y number := 0 ;
z number ;
code1 number ;
code_name varchar2(15);
begin
for i in 0 .. x
loop
select length(t.tcd_codes ) into x from hcc_patient_sheet t where t.id = p_id ; --- (9)العدد كامل
select instr(tcd_codes, ':') into y from hcc_patient_sheet t where t.id = p_id ; ---- عدد الكود الاو(3)ل
select instr(tcd_codes, ':')+1 + y into z from hcc_patient_sheet t where t.id = p_id ; --عدد الكود كامل +1
enter code here
i := x -y ;
select substr(t.tcd_codes,z, instr(tcd_codes, ':')-1) into code1
--,select substr(t.tcd_codes, 0, instr(tcd_codes, ':')-1) as code2
from Hcc_Patient_Sheet t
where t.id = 631 ;
select t.alt_name into code_name from hcc_complaint_codes t where t.code = code1 ;
select instr(tcd_codes, ':') into y from hcc_patient_sheet t where t.id = p_id ; ---- عدد الكود الاول
return code_name ;
end loop ;
end;
Often with frequent sounding string processing issues, a wheel has already been invented, and even packaged.
select * from table(apex_string.split('THIS:IS:GREAT',':'));
Partial SUBSTR doesn't seem to be the best option; I'd suggest you to split that colon-separated-values string into row as follows:
SQL> with test (col) as
2 (select '1:15:2:3' from dual)
3 select regexp_substr(col, '[^:]+', 1, level) one_value
4 from test
5 connect by level <= regexp_count(col, ':') + 1;
ONE_VALUE
--------------------------------
1
15
2
3
SQL>
and use such an option in your query; something like this:
select ...
into ...
from some_table t
where t.id in (select regexp_substr(that_string, '[^:]+', 1, level) one_value
from dual
connect by level <= regexp_count(that_string, ':') + 1
);
If it has to be row-by-row, use the above option as a source for the cursor FOR loop, as
for cur_r in (select regexp_substr(that_string, '[^:]+', 1, level) one_value
from dual
connect by level <= regexp_count(that_string, ':') + 1
)
loop
do_something_here
end loop;
I have a SEARCH package with several functions within that each return a pipelined table.
I am getting the following error:
ORA-29902: error in executing ODCIIndexStart() routine
ORA-06512: at "<SCHEMA_NAME>.SEARCH", line 955
ORA-06512: at "<SCHEMA_NAME>.SEARCH", line 216
ORA-06512: at line 1
ORA-06512: at "<SCHEMA_NAME>.SEARCH", line 1143
ORA-06512: at line 1
29902. 00000 - "error in executing ODCIIndexStart() routine"
*Cause: The execution of ODCIIndexStart routine caused an error.
*Action: Examine the error messages produced by the indextype code and
take appropriate action.
The command that I use to get this error is:
select * from table(search.user_search(10000003, '', 1, 20, 5, '', '', ''));
Here is the code around line 1143 of the SEARCH body:
FUNCTION USER_SEARCH(p_user_id number, p_search varchar2, p_page number, p_num_results number, p_concept_type_id number := null, p_standard_org varchar2 := null, p_standard_title varchar2 := null, p_standard_number varchar2 := null) RETURN SEARCH_RESULTS_TABLE AS
v_sub char(1);
v_rtn search_results_table := search_results_table();
v_user_id number;
v_page number;
v_num_results number;
v_query varchar2(4000);
cursor c_concept is
select * from table(search.concept_new(v_user_id, v_query, v_page, v_num_results, p_concept_type_id, p_standard_org, p_standard_title, p_standard_number));
BEGIN
v_page := p_page;
v_num_results := p_num_results;
v_query := p_search;
if (v_query = '') then
v_query := null;
end if;
-- ONLY DURING DEVELOPMENT
v_user_id := p_user_id;
if v_user_id = 0 then
v_user_id := 2;
end if;
if v_page = null then
v_page := 1;
end if;
if v_num_results = null then
v_num_results := -1;
end if;
select security.has_permission(p_user_id, 'UNLIMITED_RESULTS') into v_sub from dual;
case v_sub
when 'N' then
v_rtn := search.term(v_user_id, p_search, 1, 20, P_concept_type_id, p_standard_org, p_standard_title, p_standard_number);
when 'Y' then
for r_concept in c_concept loop -- line 1143
v_rtn.extend;
v_rtn(v_rtn.last) := search_results_row(r_concept.SCORE, r_concept.FROM_TABLE, r_concept.ID, r_concept.IN_DICTIONARY);
end loop;
end case;
return v_rtn;
END USER_SEARCH;
The code around line 216:
FUNCTION CONCEPT_NEW(p_user_id number, p_search varchar2, p_page number := 1, p_num_results number := -1, p_concept_type_id number := null, p_standard_org varchar2 := null, p_standard_title varchar2 := null, p_standard_number varchar2 := null) RETURN SEARCH_RESULTS_TABLE PIPELINED AS
out_rec search_results_row := search_results_row(null,null,null,null);
v_num_pages number;
v_num_results number;
cursor c_count is
select count(*) cnt, ceil(count(*) / p_num_results) num_pages from (
select * from (
select rownum rn, bb.* from (
select * from (
select sum(score) score, concept_id from
(
(
select
sum(score) score,
concept_id
from
(
select
s.score + (case
when c.eotd = 'N' then
200
else
0
end) score,
ct.concept_id
from
table(search.synonym_search(p_search)) s,
term_synonym ts,
concept_term ct,
concept c
where
c.eotd = 'N' and
s.table_id = ts.synonym_id and
ts.term_id = ct.term_id and
c.concept_id = ct.concept_id
)
group by
concept_id
)
union all
(
select
sum(score) score,
concept_id
from
(
select
s.score + (case
when c.eotd = 'N' then
200
else
0
end) score,
cd.concept_id
from
table(search.definition_search(p_search)) s,
concept_definition cd,
concept c
where
c.eotd = 'N' and
s.table_id = cd.definition_id and
c.concept_id = cd.concept_id
)
group by
concept_id
)
)
group by concept_id
) order by score desc
) bb) where score > 100) where rn < 1000;
-- another cursor here called c_search (removed for cleanliness)
v_added boolean;
v_in_dict varchar(1);
v_concept_id number;
cursor c_in_dict is
select * from dictionary_concept where concept_id = v_concept_id and dictionary_id in (select dictionary_id from company_dictionary where client_company_id in (select client_company_id from users where users_id = p_user_id));
v_in_dict_result c_in_dict%rowtype;
BEGIN
open c_count;
fetch c_count into v_num_results, v_num_pages; -- line 216
close c_count;
out_rec.SCORE := v_num_results;
out_rec.FROM_TABLE := 'HEADER';
out_rec.ID := v_num_pages;
out_rec.IN_DICTIONARY := 'N';
pipe row(out_rec);
-- more code here but been removed
RETURN;
END CONCEPT_NEW;
The code around line 995:
FUNCTION STANDARD_SEARCH(p_search varchar2) RETURN RESULT_TABLE
PIPELINED
AS
out_rec result_type := result_type(null, null);
cursor c_search is
select
45 score,
source_id
from
source
where
source_title = p_search or
standard_number = p_search
union all
select
40,
source_id
from
source
where
lower(source_title) = lower(p_search) or
lower(standard_number) = lower(p_search)
union all
select
35,
source_id
from
source
where
lower(source_title) like lower(p_search) || '%' or
lower(standard_number) like lower(p_search) || '%'
union all
select
30,
source_id
from
source
where
lower(source_title) like '%' || lower(p_search) || '%' or
lower(standard_number) like '%' || lower(p_search) || '%'
union all
select
10 * contains(source_title, lower(p_search)),
source_id
from
source
where
contains(source_title, lower(p_search)) > 1
union all
select
10 * contains(standard_number, lower(p_search)),
source_id
from
source
where
contains(standard_number, lower(p_search)) > 1;
BEGIN
for r_search in c_search loop -- line 995
out_rec.SCORE := r_search.SCORE;
out_rec.TABLE_ID := r_search.SOURCE_ID;
pipe row(out_rec);
end loop;
return;
END;
Change = null to is null. Zero-length strings in Oracle are already NULL so = '' is also incorrect.
Those are some obvious bugs but the code is so complex I'm not sure if they are directly related to the errors. You may need to shrink your code down until it can fit inside a small, reproducible test case. That can take hours of work sometimes.
Another suggestion is to rethink whether you need to use pipelined functions. In my experience pipelined functions are buggy and over-used. Sometimes they can be replaced by regular SQL statements. Sometimes they can be replaced by a simpler function that returns a complete collection, instead of returning it one row at a time. Unless the collection is so ginormous that it can't reasonably fit in memory, or you need the function to return the first N results so they can be processed immediately, the pipelined feature doesn't help.
Good day Stackoverflow!
I have a query that is giving me an error: "Missing Right Parenthesis", at least, so says SQL Developer.
My query has a CASE statement within the WHERE clause that takes a parameter, and then executing a condition based on the value entered.
I've read that when using a CASE statement within a WHERE clause you have to surround the statement with parenthesis and assign it to a numeric value, e.g. "1", however doing so does not accomplish my goal.
My goal is to execute a condition in the CASE statement if that condition is met.
Would you mind taking a look and giving me some input please?
Thanks!
SELECT ...
FROM ....
WHERE 1 = 1
AND (
CASE :P_REPORT_PERIOD
WHEN 'SPRING'
THEN ((fiscal_year = (EXTRACT(YEAR FROM (SYSDATE))-1) AND period >=10) OR (fiscal_year = (EXTRACT(YEAR FROM (SYSDATE))) AND period < 4))
WHEN 'FALL'
THEN ((fiscal_year = (EXTRACT(YEAR FROM (SYSDATE))) AND period >=4) OR (fiscal_year = (EXTRACT(YEAR FROM (SYSDATE))) AND period < 10))
END
) = 1
Problem Solved, THANKS to all those that attempted finding a solution.
Solution: Rather than using a CASE statement, I just created a stored procedure, replaced the CASE with IF and built a VSQL string from my query.
Example:
VSQL := 'SELECT.....'
IF (v_rpt_pd = 'SPRING') THEN
VSQL := VSQL || '( ( AND EXTRACT(YEAR FROM (SYSDATE))-1 = fiscal_year and period >=10) or ';
VSQL := VSQL || ' ( AND EXTRACT(YEAR FROM (SYSDATE)) = fiscal_year and period <=3) )';
ELSE
VSQL := VSQL || '( ( AND EXTRACT(YEAR FROM (SYSDATE)) = fiscal_year and period >=4) or ';
VSQL := VSQL || ' ( AND EXTRACT(YEAR FROM (SYSDATE)) = fiscal_year and period <=9) )';
END IF;
VSQL := VSQL ||' GROUP BY fiscal_year, period
and so on, if you want the entire solution, DM me and I'll send you the code.
Cheers!
As per Tom the CASE syntax in WHERE CLAUSE is -
--Syntax
select * from <table name>
where 1=1
and
(case
when <BOOLEAN_EXPRESSION>
then <SCALAR_RETURN_VALUE>
...
ELSE <SCALAR_RETURN_VALUE>
end) = <SCALAR_VALUE> ;
Example:
--Query
WITH SAMPLE_DATA AS
(select 100 COL1,999 COL2 from DUAL UNION ALL
select 200 COL1,888 COL2 from DUAL
)
SELECT * FROM SAMPLE_DATA
WHERE 1=1
AND (
CASE COL2
WHEN 999 THEN 1
ELSE 0
END
) = 1 ;
-- Output:
100 999