I need to do a function with the following sql
This sql converts from numbers to letters
With
Numero as (
select 3 N from dual
)
,
PreProcesado1 as (
select N
, floor(mod(N, 10)) Unidades
from Numero
)
select N, case Unidades
when 0 then ''
when 1 then 'one'
when 2 then 'two'
when 3 then 'three'
when 4 then 'four'
when 5 then 'five'
when 6 then 'six'
when 7 then 'seven'
when 8 then 'eight'
when 9 then 'nine'
end
end
from PreProcesado1;
I’m doing it like this but it doesn’t work, must have an input parameter which in this case is entry_numero and which should be converted
create or replace function fun_departamento(entry_numero number)
return varchar2 is
response varchar2(120);
begin
With
Numero as (
select entry_numero N from dual
)
,
PreProcesado1 as (
select N
, floor(mod(N, 10)) Unidades
from Numero
)
select N, case Unidades
when 0 then ''
when 1 then 'one'
when 2 then 'two'
when 3 then 'three'
when 4 then 'four'
when 5 then 'five'
when 6 then 'six'
when 7 then 'seven'
when 8 then 'eight'
when 9 then 'nine'
end
end
into response
from PreProcesado1;
return response;
end;
/
I get this error, I'd appreciate your help
PL/SQL: SQL Statement ignored
PL/SQL: ORA-00947: not enough values
This is a simpler way to do what you need:
to_char( to_date(n,'J'),'jsp')
For example:
SQL> select to_char( to_date(4,'J'),'jsp') as n from dual;
N
----------
four
Notice that this does not handle 0, so you may need:
select
case
when n != 0 then to_char( to_date(n,'J'),'jsp')
end
from ...
Here you find something more.
As you said that you want to do it your way, then see lines #16 and #29 as
line 16: you're selecting two values (N and CASE expression)
line 29: you're trying to put 2 values into a single variable (response)
Therefore, remove N from line #16 (or add another variable to insert into).
SQL> create or replace function fun_departamento(entry_numero number)
2 return varchar2 is
3 response varchar2(120);
4 begin
5 With
6 Numero as (
7 select entry_numero N from dual
8 )
9 ,
10 PreProcesado1 as (
11 select N
12 , floor(mod(N, 10)) Unidades
13 from Numero
14 )
15 select
16 -- N, --> without it! ...
17 case Unidades
18 when 0 then ''
19 when 1 then 'one'
20 when 2 then 'two'
21 when 3 then 'three'
22 when 4 then 'four'
23 when 5 then 'five'
24 when 6 then 'six'
25 when 7 then 'seven'
26 when 8 then 'eight'
27 when 9 then 'nine'
28 end
29 into response --> ... as you're inserting into a single variable
30 from PreProcesado1;
31 return response;
32 end;
33 /
Function created.
Testing:
SQL> select fun_departamento(5) from dual;
FUN_DEPARTAMENTO(5)
--------------------------------------------------------------------------------
five
SQL>
Related
I have a query that is fetching data as follows between two dates. The query is already fetching data as follows. Since the query has lot of calculations
& is long I am just writing the final table output I am getting -
person_number OVT Hour3_code hour3_amount
10 UNP 7
10 PUB 8
10 STR 16
8 unp 7
8 PUB 8
16 UNP 8
17 10 vac 9
17 STR 8
15 UNP 6.5
15 STH 5
I want to create a query on top of this table such that if for a person number there is only "UNP" ,"STH" AND PUB in hour3_code, then cancel flag (added column) should be Y,
If there are more values in HOUR3_CODE like -STR or there is value for OVT column then it should be N.
So expected output is -
person_number OVT Hour3_code hour3_amount CANCEL
10 UNP 7 N
10 PUB 8
10 STR 16
8 unp 7 Y
8 PUB 8
16 UNP 8 Y
17 10 vac 9 N
17 STR 8
15 UNP 6.5 Y
15 STH 5
So, since 8 has just UNP, PUB it has cancel_pay Y , Since 15 has only UNP STH it has Y , since 16 has UNP it has Y.
How to achieve this ?
Here's one option. Read comments within code.
Sample data:
SQL> with person (person, ovt, hour3) as
2 (select 10, null, 'unp' from dual union all
3 select 10, null, 'pub' from dual union all
4 select 10, null, 'str' from dual union all
5 --
6 select 8, null, 'unp' from dual union all
7 select 8, null, 'pub' from dual union all
8 --
9 select 16, null, 'unp' from dual union all
10 --
11 select 17, 10, 'vac' from dual union all
12 select 17, null, 'str' from dual union all
13 --
14 select 15, null, 'unp' from dual union all
15 select 15, null, 'sth' from dual
16 ),
Query begins here:
17 fails as
18 -- which PERSON rows have a wrong value in HOUR3 (or have
19 -- something in OVT) column?
20 (select distinct a.person
21 from person a
22 where exists (select null
23 from person b
24 where b.person = a.person
25 and ( b.hour3 not in ('unp', 'sth', 'pub')
26 or b.ovt is not null
27 )
28 )
29 )
30 -- CANCEL is "N" if PERSON is found in FAILS CTE; "Y" otherwise
31 select p.person, p.ovt, p.hour3,
32 case when f.person is not null then 'N' else 'Y' end as cancel
33 from person p left join fails f on f.person = p.person
34 order by p.person, p.hour3;
PERSON OVT HOUR3 CANCEL
---------- ---------- ----- ------
8 pub Y
8 unp Y
10 pub N
10 str N
10 unp N
15 sth Y
15 unp Y
16 unp Y
17 str N
17 10 vac N
10 rows selected.
SQL>
I'm working on Oracle's SQL and I would like to have the following results :
4,500,400,40 --> 4 500 400,40
5400200,00 --> 5 400 200,00
1200,988,00 --> 1 200 988,00
I tried to use REGEXP_REPLACE but with no result, so if someone could help me if would be wonderful.
Thanks.
Here's one option:
SQL> with test (col) as
2 (select '4,500,400,40' from dual union all
3 select '5400200,00' from dual union all
4 select '1200,988,00' from dual union all
5 select '28 200 600,5' from dual union all
6 select '40 500 600' from dual
7 )
8 select col,
9 to_char(
10 to_number( replace( replace(case when instr(col, ',') = 0 then col ||',00'
11 else col
12 end,
13 ' ', ','
14 ),
15 ',', ''
16 )
17 ) / 100,
18 'fm999G999G999G990D00',
19 'nls_numeric_characters = '', '''
20 ) result
21 from test;
COL RESULT
------------ -------------------
4,500,400,40 4 500 400,40
5400200,00 5 400 200,00
1200,988,00 1 200 988,00
28 200 600,5 2 820 060,05
40 500 600 40 500 600,00
SQL>
What does it do (now that it got more complicated)?
nested REPLACE:
inner checks whether source string contains comma , character; if not, appends ,00 suffix (that's for values like '40 500 600')
outer is as before - substitutes commas with an empty string
to_number converts such a string into a number
it is divided by 100
to_char formats it
I have a question in regards to how to SUM on a column only when a field is changing.
Take for example the table below:
Note that Column A and Column B are different tables. I.e. A was selected from Table X and B was selected from Table Y
SELECT X.A, Y.B
FROM X
INNER JOIN Y ON X.DATE = Y.DATE AND X.VAL1 =
Y.VAL1 AND X.VAL2 = Y.VAL2
A B
123 5
123 5
456 10
789 15
789 15
I need to sum column B on change of field on column A:
I.e. the query should return 5 + 10 + 15 = 30 (5 the first time because value in column A is 123, 10 the second time because column A changed from 123 to 456 - note that the second row was skipped because column A still contains value 123 - hence the change of field logic and so on).
I can't do a simple SUM(B) because that would return 50. I also cannot do SUM(B) OVER (PARTITION BY A) because that would do a running total by group, not by change of field.
My output needs to look like this:
A B X
123 5 5
123 5 5
456 10 15
789 15 30
789 15 30
I am trying to do this within a simple query. Is there a particular function I can use to do this?
For the simple data set provided, the following should work. You will, of course, want to review the ORDER BY clauses for correctness in your exact use case.
SELECT a
,b
,SUM(CASE WHEN a = prev_a THEN 0 ELSE b END) OVER (ORDER BY a RANGE UNBOUNDED PRECEDING) AS x
FROM (
SELECT a
,b
,LAG(a) OVER (ORDER BY a) AS prev_a
FROM {your_query}
)
This solution makes use of the LAG function, which returns the specified column from the previous result. Then the outer query's SUM gives the value only when the previous row didn't have the same value. And there is also the windowing clause involved in the SUM because you specified that you needed a running total.
Ta-daaa?
SQL> with test (a, b) as
2 (select 123, 5 from dual union all
3 select 123, 5 from dual union all
4 select 456, 10 from dual union all
5 select 789, 15 from dual union all
6 select 789, 15 from dual
7 ),
8 proba as(
9 select a, b,
10 case when a <> nvl(lag(a) over (order by a), 0) then 'Y' else 'N' end switch
11 from test
12 )
13 select a, b,
14 sum(decode(switch, 'Y', b, 0)) over (partition by null order by a) x
15 from proba
16 order by a;
A B X
---------- ---------- ----------
123 5 5
123 5 5
456 10 15
789 15 30
789 15 30
SQL>
you can also create a function and use it, see sample below,
create package test_pkg123
as
a number;
r_sum NUMBER;
function get_r_sum(p_a number, p_val NUMBER, rown NUMBER) return number;
end;
/
create or replace package body test_pkg123
as
function get_r_sum(p_a number, p_val NUMBER, rown NUMBER) return number
is
begin
if rown = 1 then
r_sum := p_val;
return r_sum;
end if;
if p_a != a then
r_sum := nvl(r_sum, 0) + nvl(p_val, 0);
end if;
a := p_a;
return r_sum;
end;
end;
/
with test (a, b) as
(select 123, 5 from dual union all
select 123, 5 from dual union all
select 456, 10 from dual union all
select 789, 15 from dual union all
select 789, 15 from dual union all
select 789, 15 from dual union all
select 123, 2 from dual
)
select a, b, test_pkg123.get_r_sum(a, b, rownum) r_sum
from test;
Output:
A B R_SUM
123 5 5
123 5 5
456 10 15
789 15 30
789 15 30
789 15 30
123 2 32
7 rows selected
I'm searching for a way to get a list of special characters and how many times they appear in my column. I've tried using using regexp_count which works, but I'm not sure how to extend it to make it work for all special characters in one query.
For example for syntax = 'x=y*100' with the following query I get
select *
from (
select regexp_count(syntax, '\*') as charCnt, syntax
from tblTemp
)
where charCnt > 0
charCnt=1 and syntax='x=y*100'.
Which is correct but I want to be able to get back
specChar Cnt
\* 1
= 1
etc..
Oracle Setup:
CREATE TABLE table_name(
id INT,
value NVARCHAR2(200)
);
INSERT INTO table_name
SELECT 1, N'y=20x+3' FROM DUAL UNION ALL
SELECT 2, N'***^%$%$%*&*.&\?' FROM DUAL UNION ALL
SELECT 3, UNISTR('\00B5\00B6\00B5') FROM DUAL UNION ALL
SELECT 4, N'!"£$%^&*()!"£$%^&*()!"£$%^&*()!"£$%^&*()!"£$%^&*()'
|| N'!"£$%^&*()!"£$%^&*()!"£$%^&*()!"£$%^&*()!"£$%^&*()'
|| N'!"£$%^&*()!"£$%^&*()!"£$%^&*()!"£$%^&*()!"£$%^&*()'
|| N'!"£$%^&*()!"£$%^&*()!"£$%^&*()!"£$%^&*()!"£$%^&*()' FROM DUAL;
CREATE OR REPLACE TYPE CHAR_LIST IS TABLE OF CHAR(1 CHAR);
/
Query:
SELECT t.id,
--MAX( t.value ) AS value,
CAST( c.COLUMN_VALUE AS CHAR(1 CHAR) ) AS character,
COUNT(1) AS frequency
FROM table_name t,
TABLE(
CAST(
MULTISET(
SELECT SUBSTR( t.value, LEVEL, 1 )
FROM DUAL
WHERE REGEXP_LIKE( SUBSTR( t.value, LEVEL, 1 ), '[^a-zA-Z0-9]' )
CONNECT BY LEVEL <= LENGTH( t.value )
) AS CHAR_LIST
)
) c
GROUP BY t.id, c.COLUMN_VALUE
ORDER BY id, character;
Output:
ID CHARACTER FREQUENCY
---------- --------- ----------
1 + 1
1 = 1
2 $ 2
2 % 3
2 & 2
2 * 5
2 . 1
2 ? 1
2 \ 1
2 ^ 1
3 µ 2
3 ¶ 1
4 ! 20
4 " 20
4 $ 20
4 % 20
4 & 20
4 ( 20
4 ) 20
4 * 20
4 ^ 20
4 £ 20
I have a stored procedure which receives three string parameters
1. p_ReqIDs VARCHAR2
2. p_ItemIDs VARCHAR2
3. p_Qtys VARCHAR2
The above 3 string variables contain semicolon-separated values like this:
p_ReqIDs := "56;56;56;"
p_ItemIDs := "3;2;1;"
p_Qtys := "400;300;200;"
I need to split values and create rows like this:
p_ReqIDs p_ItemIDs p_Qtys
------------------------------------
56 3 400
56 2 300
56 1 200
I need the query which splits and insert into table also.
Thanks
You could process parameters as follows:
SQL> declare
2 type l_rec_type is record(
3 r_ReqIDs varchar2(31),
4 r_ItemIDs varchar2(31),
5 r_Qtys varchar2(31)
6 );
7
8 type l_rec_list is table of l_rec_type;
9 -- your parameters.
10 l_ReqIDs constant varchar2(31) := '56;56;56;';
11 l_ItemIDs constant varchar2(31) := '3;2;1;';
12 l_Qtys constant varchar2(31) := '400;300;200;';
13
14 l_rec l_rec_list;
15 begin
16
17 with Parameters(param) as(
18 select l_ReqIDs from dual union all
19 select l_ItemIDs from dual union all
20 select l_Qtys from dual
21 ),
22 Occurrences(oc) as(
23 select level
24 from ( select max(regexp_count(param, '[^;]+')) moc
25 from parameters) s
26 connect by level <= s.moc
27 )
28 select max(res1)
29 , max(res2)
30 , max(res3)
31 bulk collect into l_rec
32 from (select decode(param, l_ReqIDs, res) res1
33 , decode(param, l_ItemIDs,res) res2
34 , decode(param, l_Qtys, res) res3
35 , rn
36 from ( select param, regexp_substr(param, '[^;]+', 1, o.oc) res
37 , row_number() over(partition by param order by param) rn
38 from parameters p
39 cross join occurrences o
40 )
41 )
42 group by rn;
43
44 for i in l_rec.first..l_rec.last
45 loop
46 dbms_output.put_line(l_rec(i).r_ReqIDs || ' ' || l_rec(i).r_ItemIDs || ' ' || l_rec(i).r_Qtys);
47 end loop;
48 end;
49 /
56 2 200
56 1 300
56 3 400
PL/SQL procedure successfully completed
If you need to just insert processed data into a table the only insert into statement and query will be needed (bulk collect into l_rec must be removed):
insert into your_table(<<columns>>)
with Parameters(param) as(
select l_ReqIDs from dual union all
select l_ItemIDs from dual union all
select l_Qtys from dual
....
-- the rest of the query from the above pl/sql block.
You also can insert an entire record into a table(in a case you need to do extra processing of extracted elements before insertion) as follows:
If number of columns in a table equal to number of elements being inserted
for i in l_rec.first..l_rec.last
loop
insert into your_table
values l_rec(i);
end loop;
If number of columns in a table is greater then the number of values being inserted
for i in l_rec.first..l_rec.last
loop
insert into (select column1, .. ,columnn from your_table)
values l_rec(i);
end loop;
i did like this :) short and sweet.
create or replace procedure proc1(p_ReqID varchar2,p_ItemID varchar2,p_ItemQty varchar2)
is
begin
insert into test(req_id,item_id,itemqty)
select regexp_substr(req_id,'[^;]+',1,level),
regexp_substr(item_id,'[^;]+',1,level),
regexp_substr(item_qty,'[^;]+',1,level)
from (
select p_ReqID Req_ID,p_ItemID item_id,p_ItemQty item_qty
from dual
)
connect by regexp_substr(req_id,'[^;]+',1,level) is not null;
end;