i'm new to sql and pl/sql. To practice I was giving an assignment to make a calculator. That part works. But they also want the possibility to type the calculation in the text field and then it needs to work. For example 4+4 (then the = button or enter on your keyboard) or 4+6-3=.
My calculator with buttons works, but not if I type a calculation in the text field. Can anyone help me with this?
This is the code I have in my total:
declare
l_operator varchar2(1) := :P3_OPERATOR;
l_value1 number := :P3_VALUE1;
l_value2 number := :P3_VALUE2;
l_result number := nvl(:P3_VALUE1,0);
begin
case l_operator
when '+' then
l_result := l_value1 + l_value2;
when '-' then
l_result := l_value1 - l_value2;
when '*' then
l_result := l_value1 * l_value2;
when '/' then
l_result := l_value1 / l_value2;
else
null;
end case;
:P3_OPERATOR := null;
:P3_VALUE2 := null;
:P3_VALUE1 := l_result;
:P3_NUMBERFIELD := l_result;
end;
with this for als extra for the +, -, * and \ .
:P12_OPERATOR := '*';
:P12_NUMBERFIELD := :P12_OPERATOR;
and this is the code for all my number buttons:
begin
if :P12_OPERATOR is null then
:P12_VALUE1 := :P12_VALUE1 || 4;
:P12_NUMBERFIELD := :P12_VALUE1;
elsif :P12_OPERATOR is not null then
:P12_VALUE2 := :P12_VALUE2 || 4;
:P12_NUMBERFIELD := :P12_VALUE2;
end if;
end;
This is not a typical way to use SQL or PL/SQL (or APEX which it looks like you are also using)!
You could evaluate any expression typed in with code like this:
begin
execute immediate 'select ' || :P3_NUMBERFIELD || ' from dual' into l_result;
exception
when others then
l_result := 'Invalid input';
end;
The exception part is to stop the calculator going wrong if the user types in nonsense like "hello world" instead of an arithmetic expression. The user would need to type in an expression like 4+4 without typing the equals sign, and then press a button to invoke the process to calculate the result.
Any idea what is the difference betweet this:
p_persist_reg_CRC_calc: process (Clk_50Mhz)
begin
if falling_edge(Clk_50Mhz) then
if crc_rx_init <= '0' then
flash_crc_calc <= (others =>'1');
else
flash_crc_calc <= (others =>'0');
end if;
end if;
end process p_persist_reg_CRC_calc;
and this:
p_persist_reg_CRC_calc: process (Clk_50Mhz)
begin
if falling_edge(Clk_50Mhz) then
if crc_rx_init <= '1' then
flash_crc_calc <= (others =>'0');
else
flash_crc_calc <= (others =>'1');
end if;
end if;
end process p_persist_reg_CRC_calc;
The second stack to zero.
In my understanding they should be the same as function.
Regards,
Emil
Most likely a typo: try
if crc_rx_init = '1' then
( '0' and '1' are both <= '1' )
Assuing crc_rx_init is a std_logic, then the only difference is likely in simulation.
Remember, std_logic has 9 states ('U', '0', '1', 'X', 'Z', 'L', 'H', 'W', '-'). In the first case, if crc_rx_init was 'U', then flash_crc_calc would be all '0'. In the second case, flash_crc_calc would be all '1'.
I have the following code:
declare
l_input clob;
l_output clob;
function check_this_regex(
io_str in out clob
,o_found out clob
) return boolean
is
l_match clob;
begin
dbms_output.put_line('Matching against ->' || io_str || '<-');
l_match := regexp_substr(io_str, '"((y)*)"');
if l_match is null then
return false;
end if;
o_found := l_match;
return true;
end;
begin
l_input := to_clob('x');
dbms_output.put_line('l_input->' || l_input || '<-');
if (check_this_regex(l_input, l_output)) then
dbms_output.put_line('Found: ' || l_output);
else
dbms_output.put_line('Not found');
end if;
end;
Why does this output Found?
The problem should be checking a clob against NULL; editing your check this way
if l_match /* is null */ = empty_clob() then
gives :
l_input->x<-
Matching against ->x<-
Not found
regexp_substr for clob alwas returns not null value.Check example.
declare
v_clob clob;
v_in clob :='a';
v_str varchar2(10);
v_st_in varchar2(10) :='a';
begin
v_clob := regexp_substr(v_in,'xx');
if v_clob is null then
dbms_output.put_line('aaa');
end if;
v_str := regexp_substr(v_st_in,'xx');
if v_str is null then
dbms_output.put_line('aaa');
end if;
end;
I don't know why its showing error although syntax seems to be right.
I'm t rying to program sramctl where address adds_in is input address and sram_adds output address I am just mapping the address and have not consider the data bus.
library IEEE;
use IEEE.std_logic_1164.all;
entity sramctrl is
port(clk,adsn,blastn,lwdrn,lhold:in std_logic;
adds_in :in std_logic_vector(9 downto 2);
adds_4msb:in std_logic_vector(31 downto 28);
readyn,btermn,sramcsn,sramoen,lholda :out std_logic;
sram_adds:out std_logic_vector(9 downto 2));
end sramctrl;
architecture behavioral of sramctrl is
type state_type is(s0,s1,s2);
signal state:state_type;
begin
process(clk,adsn,blastn,lwdrn,lhold,adds_in,adds_4msb)
begin
variable sa:std_logic:='0';
variable a31_a28 :std_logic_vector(3 downto 0):="0000";
variable temp:std_logic_vector(9 downto 2):="00000000";
if(rising_edge(clk))then
if ((not adsn) and (adds_4msb="0000"))then
a31_28 := adds_4msb;
end if;
if (lhold='1')then
lholda<='1';
else
lholda<='0';
end if;
sa:=lhold and lholda ;
case state is
when s0=>sramoen<='1';
sramcsn<='1';
readyn<='1';
btermn<='1';
if((not adsn) and (not adds_4msb) and sa)then
temp:=adds_in;
if(lwdrn='1')then
state<=s1;
ready<='0';
else
state<=s2;
end if;
else
state<=s0;
end if;
when s1=>sramoen<='1';
sramcsn<='0';
if(lwdrn and (not blastn) and sa)then
sram_adds<=temp;
readyn<='1';
btermn<='1';
state<=s0;
elsif(lwdrn and blastn and sa)then
if(temp=X"fe")then
sram_adds<=temp;
temp:=temp+1;
btermn<='0';
readyn<='0';
state<=s1;
elsif(temp=X"ff")then
sram_adds<=temp;
btermn<='1';
readyn<='1';
state<=s0;
else
sram_adds<=temp;
temp:=temp+1;
btermn<='1';
readyn<='0';
state<=s1;
end if;
else
state<=s2;
end if;
when s2=>sramoen<='0';
sramcsn<='0';
if((not lwdrn) and (not blastn) and sa)then
sram_adds<=temp;
readyn<='1';
btermn<='1';
state<=s0;
elsif((not lwdrn) and blastn and sa)then
if(temp=X"fe")then
sram_adds<=temp;
temp:=temp+1;
btermn<='0';
readyn<='0';
state<=s2;
elsif(temp=X"ff")then
sram_adds<=temp;
btermn<='1';
readyn<='1';
state<=s0;
else
sram_adds<=temp;
temp:=temp+1;
btermn<='1';
readyn<='0';
state<=s2;
end if;
else
state<=s2;
end if;
when others =>state<=s0;
end case;
end if;
end process;
end behavioral ;
I couldn't find a solution please help me out. Errors it has popped:
COMP96 Compile Architecture "behavioral" of Entity "sramctrl"
COMP96 ERROR COMP96_0019: "Keyword 'end' expected." "design.vhd" 18 9
COMP96 ERROR COMP96_0019: "Keyword 'end' expected." "design.vhd" 19 3
COMP96 ERROR COMP96_0016: "Design unit declaration expected." "design.vhd"
No your syntax isn't correct.
As noted by Amir :
process(clk,adsn,blastn,lwdrn,lhold,adds_in,adds_4msb)
begin
variable sa:std_logic:='0';
variable a31_a28 :std_logic_vector(3 downto 0):="0000";
variable temp:std_logic_vector(9 downto 2):="00000000";
Should be:
process(clk,adsn,blastn,lwdrn,lhold,adds_in,adds_4msb)
variable sa:std_logic:='0';
variable a31_a28 :std_logic_vector(3 downto 0):="0000";
variable temp:std_logic_vector(9 downto 2):="00000000";
begin
begin separates the process declarative part from the process statement part here.
Also, here:
if ((not adsn) and (adds_4msb="0000"))then
There isn't an and operator that ANDs a std_logic and a boolean (result of the right expression).not is not a logical reduction operator, it returns a std_logic in this case.
should be along the lines of:
if adsn = '0' and adds_4msb = "0000" then
Which ANDs two boolean results. Notice the corrected spelling of adds_4msb.
The next line:
a31_28 := adds_4msb;
has a misspelling, that should be a31_a28.
And here::
if lhold = '1' then
lholda <= '1';
else
lholda <= '0';
end if;
sa := lhold and lholda ;
lholda is an output and in some tools not IEEE Std 1076-2008 compliant can not be read. It also produces a sa that's simply delayed by one delta simulation cycle (no time advancing) and has no meaning other that to trim a delta cycle off the end of holda for sa or off the beginning of lhold. If you're counting on that delta cycle hold over not being there you have a defective design. Delta cycles emulate parallelism and variables shouldn't be counted on for timing relationships. This would imply you don't have a synthesis eligible model of sram_ctl. Synthesis would see lhold and lholda as one and the same, and sa as a different name for the same thing.
Here:
ready<='0';
There is no signal ready present in your design.
And:
if(lwdrn and (not blastn) and sa)then
as well as:
elsif(lwdrn and blastn and sa)then
You're trying to produce a boolean condition with logic operators. (All those parentheses are also redundant) try conditional testing the two expressions to a std_logic value.
These two conditions show up two places each.
And:
temp:=temp+1;
There is no adding operator "+" directly visible (two places). You should either be using package std_logic_unsigned or temp should be an unsigned and you should be using package numeric_std (requiring a type conversion when assigning to sram_adds).
I have quite a number of text fields I need to deal with. In order to process them the first thing I need to do is to normalize the set of characters I deal with. I need my output string to contain the following;
A-Z, 0-9 and space and I want all lower case converted to upper case.
So I use the following in pl/sql;
X := UPPER(TRIM(REGEXP_REPLACE
(REGEXP_REPLACE(X, '[^0-9A-Za-z ]', ' '),'( )* ',' ')));
This is rather slow. What would be faster?
You can try this approach, which looks to be much faster based on some (very) loose tests. Its a function that's compiled natively:
CREATE OR REPLACE function clean_string(
in_string in varchar2)
return varchar2 AS
out_string varchar2(4000) := '';
in_length number;
cnt number := 0;
in_char char(1);
out_char char(1);
dec_char number;
prev_space boolean := false;
begin
--dbms_output.put_line('In string: ' || in_string);
in_length := LENGTH(in_string);
while cnt < in_length
LOOP
cnt := cnt + 1;
in_char := substr(in_string, cnt, 1);
dec_char := ascii(in_char);
-- blank out non alphanumerics
IF (
(dec_char >= 48 AND dec_char <= 57) OR
(dec_char >= 65 AND dec_char <= 90) OR
(dec_char >= 97 AND dec_char <= 122)
) THEN
--keep it
out_char := in_char;
ELSE
out_char := ' ';
END IF;
IF (NOT(prev_space AND out_char = ' ')) THEN
out_string := out_string || out_char;
END IF;
<<endloop>>
IF (out_char = ' ') THEN
prev_space := true;
ELSE
prev_space := false;
END IF;
END LOOP;
return trim(upper(out_string));
end;
ALTER SESSION SET PLSQL_CODE_TYPE=NATIVE;
ALTER function clean_string COMPILE;
And to test, I pulled 5 million rows from a table and cleaned some strings:
set serveroutput on
declare
cursor sel_cur1 is
select name, clean_string(name) as cln_name,
address1, clean_string(address1) as cln_addr1,
address2, clean_string(address2) as cln_addr2,
city, clean_string(city) as cln_city,
state, clean_string(state) as cln_state,
postalcode, clean_string(postalcode) as cln_zip
from my_table
where rownum <= 5000000;
cursor sel_cur2 is
select name,
address1,
address2,
city,
state,
postalcode
from my_table
where rownum <= 5000000;
l_cnt integer := 0;
l_cln_name varchar2(100);
l_cln_addr1 varchar2(100);
l_cln_addr2 varchar2(100);
l_cln_city varchar2(100);
l_cln_state varchar2(100);
l_cln_zip varchar2(100);
l_interval interval day to second(4);
l_start timestamp;
l_end timestamp;
begin
l_start := systimestamp;
for rec in sel_cur2
loop
l_cnt := l_cnt + 1;
l_cln_name := clean_string(rec.name);
l_cln_addr1 := clean_string(rec.address1);
l_cln_addr2 := clean_string(rec.address2);
l_cln_city := clean_string(rec.city);
l_cln_state := clean_string(rec.state);
l_cln_zip := clean_string(rec.postalcode);
end loop;
l_end := systimestamp;
l_interval := l_end - l_start;
dbms_output.put_line('Procedural approach timing: ' || l_interval);
-------------------------------------------------
l_cnt := 0;
l_start := systimestamp;
for rec in sel_cur1
loop
-- cleaning already done in SQL
l_cnt := l_cnt + 1;
end loop;
l_end := systimestamp;
l_interval := l_end - l_start;
dbms_output.put_line('SQL approach timing: ' || l_interval);
-------------------------------------------------
l_cnt := 0;
l_start := systimestamp;
for rec in sel_cur2
loop
l_cnt := l_cnt + 1;
l_cln_name := UPPER(TRIM(REGEXP_REPLACE(REGEXP_REPLACE(rec.name, '[^0-9A-Za-z ]', ' '),'( )* ',' ')));
l_cln_addr1 := UPPER(TRIM(REGEXP_REPLACE(REGEXP_REPLACE(rec.address1, '[^0-9A-Za-z ]', ' '),'( )* ',' ')));
l_cln_addr2 := UPPER(TRIM(REGEXP_REPLACE(REGEXP_REPLACE(rec.address2, '[^0-9A-Za-z ]', ' '),'( )* ',' ')));
l_cln_city := UPPER(TRIM(REGEXP_REPLACE(REGEXP_REPLACE(rec.city, '[^0-9A-Za-z ]', ' '),'( )* ',' ')));
l_cln_state := UPPER(TRIM(REGEXP_REPLACE(REGEXP_REPLACE(rec.state, '[^0-9A-Za-z ]', ' '),'( )* ',' ')));
l_cln_zip := UPPER(TRIM(REGEXP_REPLACE(REGEXP_REPLACE(rec.postalcode, '[^0-9A-Za-z ]', ' '),'( )* ',' ')));
end loop;
l_end := systimestamp;
l_interval := l_end - l_start;
dbms_output.put_line('Existing approach timing: ' || l_interval);
end;
And the output was:
Procedural approach timing: +00 00:02:04.0320
SQL approach timing: +00 00:02:49.4326
Existing approach timing: +00 00:05:50.1607
Also, the native compilation seems to only help a procedural approach to the processing (rather than calling the function from a SQL query), but appears to be much faster than the regexp_replace solution. Hope that helps.
First, let me say that I am not really answering my own question, but I am accepting tbone's answer. The reason for providing this answer, is the comments don't let me post what I really want.
I created a function almost identical to tbone's with a couple of tweaks, got rid of the UPPER by changing how I handle the lower case range of characters, and changed numbers to binary_integers.
FUNCTION CLEAN_STRING(IN_STRING in VARCHAR2) RETURN VARCHAR2
AS
OUT_STRING VARCHAR2(32767) := '';
IN_LENGTH BINARY_INTEGER;
CNT BINARY_INTEGER := 0;
IN_CHAR CHAR(1);
OUT_CHAR CHAR(1);
DEC_CHAR BINARY_INTEGER;
PREV_SPACE BOOLEAN := FALSE;
BEGIN
IN_LENGTH := LENGTH(IN_STRING);
WHILE CNT < IN_LENGTH
LOOP
CNT := CNT + 1;
IN_CHAR := SUBSTR(IN_STRING, CNT, 1);
DEC_CHAR := ASCII(IN_CHAR);
-- blank out non alphanumerics
IF ((DEC_CHAR >= 48 AND DEC_CHAR <= 57) OR
(DEC_CHAR >= 65 AND DEC_CHAR <= 90))
THEN
--keep it
OUT_CHAR := IN_CHAR;
ELSE
IF (DEC_CHAR >= 97 AND DEC_CHAR <= 122)
THEN
OUT_CHAR := CHR(DEC_CHAR - 32);
ELSE
OUT_CHAR := ' ';
END IF;
END IF;
IF (NOT(PREV_SPACE AND OUT_CHAR = ' '))
THEN
OUT_STRING := OUT_STRING || OUT_CHAR;
END IF;
<<endloop>>
IF (OUT_CHAR = ' ') THEN
PREV_SPACE := TRUE;
ELSE
PREV_SPACE := FALSE;
END IF;
END LOOP;
RETURN TRIM(OUT_STRING);
END CLEAN_STRING;
I then created a simple test rig like tbone did, but I tested the three different routines against each other. First I verify that they all return the same results and then time each routine. Here is the test rig;
set serveroutput on
DECLARE
CURSOR PATHMAST_CURS
IS
SELECT PATHMAST_TEXT_DIAGNOSIS FROM PATHMAST WHERE ROWNUM < 100000;
DUMMY CLOB;
DUMMY_1 CLOB;
DUMMY_2 CLOB;
l_interval interval day to second(4);
l_start timestamp;
l_end timestamp;
diff_count_1 binary_integer := 0;
diff_count_2 binary_integer := 0;
BEGIN
FOR PATH_REC IN PATHMAST_CURS
LOOP
DUMMY := UPPER(TRIM(REGEXP_REPLACE(REGEXP_REPLACE(NVL(PATH_REC.PATHMAST_TEXT_DIAGNOSIS,' '), '[^0-9A-Za-z ]', ' '),'( )* ',' ')));
DUMMY_1 := pathmast_utility_3.CLEAN_STRING(NVL(PATH_REC.PATHMAST_TEXT_DIAGNOSIS,' '));
DUMMY_2 := regexp_replace(trim(translate(NVL(PATH_REC.PATHMAST_TEXT_DIAGNOSIS,' '),'abcdefghijklmnopqrstuvwxyz`~!##$%^&*()''_+-={[}]|/\":;,.<>?µ’±€'||chr(9),'ABCDEFGHIJKLMNOPQRSTUVWXYZ ')),'( )* ',' ');
IF DUMMY_1 != DUMMY
THEN
diff_count_1 := diff_count_1 + 1;
END IF;
IF DUMMY_2 != DUMMY
THEN
diff_count_2 := diff_count_2 + 1;
dbms_output.put_line('Regexp: ' || DUMMY);
dbms_output.put_line('Translate: ' || DUMMY_2);
END IF;
END LOOP;
dbms_output.put_line('CLEAN_STRING differences: ' || diff_count_1);
dbms_output.put_line('Translate differences: ' || diff_count_2);
l_start := systimestamp;
FOR PATH_REC IN PATHMAST_CURS
LOOP
DUMMY := UPPER(TRIM(REGEXP_REPLACE(REGEXP_REPLACE(PATH_REC.PATHMAST_TEXT_DIAGNOSIS, '[^0-9A-Za-z ]', ' '),'( )* ',' ')));
END LOOP;
l_end := systimestamp;
l_interval := l_end - l_start;
dbms_output.put_line('Regexp approach timing: ' || l_interval);
-------------------------------------------------
l_start := systimestamp;
FOR PATH_REC IN PATHMAST_CURS
LOOP
DUMMY := pathmast_utility_3.CLEAN_STRING(PATH_REC.PATHMAST_TEXT_DIAGNOSIS);
END LOOP;
l_end := systimestamp;
l_interval := l_end - l_start;
dbms_output.put_line('CLEAN_STRING approach timing: ' || l_interval);
-------------------------------------------------
l_start := systimestamp;
FOR PATH_REC IN PATHMAST_CURS
LOOP
DUMMY := regexp_replace(trim(translate(NVL(PATH_REC.PATHMAST_TEXT_DIAGNOSIS,' '),'abcdefghijklmnopqrstuvwxyz`~!##$%^&*()''_+-={[}]|/\":;,.<>?µ’±€'||chr(9),'ABCDEFGHIJKLMNOPQRSTUVWXYZ ')),'( )* ',' ');
END LOOP;
l_end := systimestamp;
l_interval := l_end - l_start;
dbms_output.put_line('TRANSLATE approach timing: ' || l_interval);
-------------------------------------------------
END;
And here are the results;
anonymous block completed
CLEAN_STRING differences: 0
Translate differences: 0
Regexp approach timing: +00 00:00:52.9160
CLEAN_STRING approach timing: +00 00:00:05.5220
TRANSLATE approach timing: +00 00:00:13.4320
This is all without compiling native. So tbone is the big winner. Thank you tbone.
If for whatever reason you want/need to use the translate version, you should build the translate string programmatically in order to get all of the special characters.
Perhaps, you can use TRANSLATE instead of regex to remove special characters and convert lower case to upper case.
regexp_replace(
trim(
translate(x,
'abcdefghijklmnopqrstuvwxyz`~!##$%^&*()_+-={[}]|/\"'':;,.<>?',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ '
)
),
' {2,}',
' '
)
Tried it on a table with 1000 rows and column with random characters from anywhere between 1 to 4000.
Resulted in around 35% less time.(Did not try in PLSQL).