I want to insert the data to PL-SQL.
But I need to check whether the table has similar Data.
If the table check has similar information, it cannot be added
exanple:
Insert Data : ABCD or ABCE
Table:
enter image description here
The Tabel Device has ABC,so it cannot be added.
How can I write this program?
You can use instr in plsql
example:
declare
x number;
begin
for i in (select distinct value from table)
loop
select count(1) into x
from table2
where instr(Device, i.value) > 0;
if (x = 0) then
insert into table2(Device) values(i.value);
end if;
commit;
end loop;
end;
Similar or the same data? That makes a huge difference. Because if you don't want the same data in your columns, you can just make the column unique. But if you want to check for similar data, welp, that's kind of hard to implement, hard to understand, and that just outright kills your performance...But if you still want to go that way, you can check out Jaro-Winkler Algorithm
Isi already mentioned the algorithm; here's an example of what you might be looking for.
Current table contents:
SQL> select * from test;
COL
-----
ABC
ABD
ABR
Here's how similar current values are to certain strings (ABCD, FDGH) you'd want to insert:
SQL> select t.col,
2 utl_match.jaro_winkler_similarity('ABCD', t.col) sim_abcd,
3 utl_match.jaro_winkler_similarity('FDGH', t.col) sim_fdgh
4 from test t;
COL SIM_ABCD SIM_FDGH
----- ---------- ----------
ABC 94 0
ABD 93 52
ABR 77 0
Now, it is up to you to decide which value will represent a limit and either insert a value into that table or not. Let's presume it is 90%. Then you'd
SQL> insert into test (col)
2 select '&&par_insert'
3 from dual
4 where 90 > (select max(utl_match.jaro_winkler_similarity('&&par_insert', a.col))
5 from test a
6 );
Enter value for par_insert: ABCD
0 rows created.
SQL>
Right; ABCD is similar to any of current values more than 90% and wasn't inserted.
How about FDGH?
SQL> undefine par_insert
SQL> /
Enter value for par_insert: FDGH
1 row created.
SQL> select * from test;
COL
-----
ABC
ABD
ABR
FDGH
SQL>
Yes, it was inserted.
Related
I have a table:
id
name
amount
If the same name was inserted, then amount should be incremented.
Else, insert with 0 amount.
How to create a trigger with a given condition?
You shouldn't really be doing that. AMOUNT column effectively counts number of NAME appearances in that table. You can always count it, can't you? So, what's the purpose of doing that?
If you want to know which name was inserted prior (or after) some other name (equal to the previous one), sort them by ID (if it is incremental, such as an identity column or if it gets its value from a sequence).
If ID isn't incremental, add DATE_INSERTED column (and sort by it; or apply ROW_NUMBER analytic function which orders values by DATE_INSERTED).
Also, what happens if you delete one of those duplicate names? Will you retroactively decrement AMOUNT column for all previous instances of that NAME?
But, if you insist, here's one option. As you can't just select from a table you're inserting into (because of the mutating table error), I'm using a compound trigger. The part of "insert amount 0" is done by setting the column's default value (you don't need any code for that).
SQL> create table test
2 (id number primary key,
3 name varchar2(20),
4 amount number default 0);
Table created.
SQL> create or replace trigger trg_ai_test
2 for insert on test
3 compound trigger
4
5 type test_rt is record (id test.id%type,
6 name test.name%type);
7 type rli_t is table of test_rt index by pls_integer;
8 g_rli rli_t;
9
10 after each row is
11 begin
12 g_rli(g_rli.count + 1).id := :new.id;
13 g_rli(g_rli.count).name := :new.name;
14 end after each row;
15
16 after statement is
17 l_cnt number;
18 begin
19 for i in 1 .. g_rli.count loop
20 dbms_output.put_Line('x');
21 dbms_output.put_line(i ||' '|| g_rli(i).id ||' '||g_rli(i).name);
22 select count(*) into l_cnt
23 from test
24 where name = g_rli(i).name;
25
26 update test set
27 amount = l_cnt
28 where id = g_rli(i).id;
29 end loop;
30
31 end after statement;
32 end trg_ai_test;
33 /
Trigger created.
SQL>
Testing:
SQL> insert into test (id, name) values (1, 'little');
1 row created.
SQL> insert into test (id, name) values (2, 'foot');
1 row created.
SQL> insert into test (id, name) values (3, 'little');
1 row created.
SQL> insert into test (id, name) values (9, 'little');
1 row created.
SQL> select * from test;
ID NAME AMOUNT
---------- -------------------- ----------
1 little 1
2 foot 1
3 little 2
9 little 3
SQL>
Or, a simpler solution (described above), without using that much code:
SQL> select id, name,
2 row_number() over (partition by name order by id) as amount
3 from test;
ID NAME AMOUNT
---------- -------------------- ----------
2 foot 1
1 little 1
3 little 2
9 little 3
SQL>
I have an Oracle table with 4 columns (Name, Phone, Email, Count).
If the user is updating value of Name column, then I need to increment Count column value by 1.
If the user is updating values other than Name column, then I don't need to increment Count column value by 1.
Initially, when the record is inserted, Count should be 0. And every time when Name column is updated, the Count should be incremented by 1 (like 1, 2, 3 .....).
How we can achieve this? I am very new to databases.
Thanks a lot for your help.
You can do that in an update and insert trigger or in your program. The later however requires all possible programs to cooperate. The former (triggers) is black art.
A program can do it like this:
UPDATE Person SET Count=Count+1, Phone='123' WHERE name=`csr` and Phone <> '123';
This will update one or no record (i.e. if phone was already 123 it will do nothing).
BTW: there is no nice solution to insert it if it was missing.
Hmm, you changed your question, updating the Name is problematic if you do not have another primary key, is that really what you want?
If you are looking at plsql procedure, then you can use this method,
I am using 3 input variables,
1.) column name to edit
2.) old value
3.) New value to be updated
SQL> create or replace procedure updateval (colname varchar2,oldval varchar2,newval varchar2) is
2 l_prop varchar2(10);
3 l_newval varchar2(10);
4 l_old_val varchar2(10);
5 begin
6 l_prop:=colname;
7 l_newval:=newval;
8 l_old_val:=oldval;
9 IF (upper(l_prop)='NAME') THEN
10 update TESTING123 set name=l_newval,count=count+1 where name=l_old_val;
11 elsif (upper(l_prop)='PHONE') THEN
12 update TESTING123 set PHONE=l_newval ,count=count+1where PHONE=l_old_val;
13 elsif (upper(l_prop)='EMAIL') THEN
14 update TESTING123 set EMAIL=l_newval ,count=count+1 where EMAIL=l_old_val;
15 END IF;
16 end;
17 /
Procedure created.
SQL>
SQL> select * from testing123;
NAME PHONE EMAIL COUNT
---------- ---------- ---------- ----------
abc1 12345 ABC#a.COM 1
xyz 3435 xyz#a.COM 0
SQL> exec updateval ('NAME','abc1','newabc1');
PL/SQL procedure successfully completed.
SQL>
SQL>
SQL> select * from testing123;
NAME PHONE EMAIL COUNT
---------- ---------- ---------- ----------
newabc1 12345 ABC#a.COM 2
xyz 3435 xyz#a.COM 0
I want to create a sequence for this varchar. It would have been easier had it been a number instead of varchar. In that case, I could do
seq_no := seq_no + 1;
But what can I do when I want to store next value in column as A0000002, when the previous value was A0000001 (to increment the number in the next varchar rowby 1)?
This can be done by
to_char(seq_no,'FM0000000')
your example can be done by creating sequence in oracle
create sequence seq_no start with 1 increment by 1;
then
select 'A'||to_char(seq_no.nextval,'FM0000000') from dual;
Right now i have used in dual ..but place this
'A'||to_char(seq_no.nextval,'FM0000000')
in your required query ..this will create sequence as you mentioned
sqlfiddle
Sequences are purely numeric. However, you need a trigger anyway, so simply adapt such trigger to insert the desired prefix:
CREATE OR REPLACE TRIGGER FOO_TRG1
BEFORE INSERT
ON FOO
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
IF :NEW.FOO_ID IS NULL THEN
SELECT 'A' || TO_CHAR(FOO_SEQ1.NEXTVAL, 'FM0000000') INTO :NEW.FOO_ID FROM DUAL;
END IF;
END FOO_TRG1;
/
ALTER TRIGGER FOO_TRG1 ENABLE;
If you're able I'd actually use a virtual column as defined in the CREATE TABLE syntax. It makes it more easily extensible should the need arise.
Here's a working example.
SQL> create table tmp_test (
2 id number(7,0) primary key
3 , col1 number
4 , seq varchar2(8 char) generated always as (
5 'A' || to_char(id, 'FM0999999'))
6 );
Table created.
SQL>
SQL> create sequence tmp_test_seq;
Sequence created.
SQL>
SQL> create or replace trigger tmp_test_trigger
2 before insert on tmp_test
3 for each row
4 begin
5
6 :new.id := tmp_test_seq.nextval;
7 end;
8 /
Trigger created.
SQL> show errors
No errors.
SQL>
SQL> insert into tmp_test (col1)
2 values(1);
1 row created.
SQL>
SQL> select * from tmp_test;
ID COL1 SEQ
---------- ---------- --------------------------------
1 1 A0000001
Having said that; you would be better off if you did not do this unless you have an unbelievably pressing business need. There is little point to making life more difficult for yourself by prepending a constant value onto a number. As A will always be A it doesn't matter whether it's there or not.
If the format is always a letter followed by 7 digits you can do:
sequence = lpad(substr(sequence,2,7)+1,7,'0')
How can we set default value for a number typed column has '00'?I tried this but it still saved it has '0',I need to do this.
//alter table table_name add column column1 default '00';
Please suggest a way for me.
You can store as number and when you retrieve do as
select column1,to_char(column2,'00') from mytable
SQL Fiddle Demo
It is not possible to store numbers like that - In a format you have described ('00'). You can store numbers as numbers (as values of numeric data type of course) and use to_char function or to_char function combined with lpad function to represent numbers in a format you like. Here is an example:
SQL> create table TB_SingleNumberColumn(
2 col number
3 )
4 /
Table created
SQL> insert into TB_SingleNumberColumn(Col) values(1);
1 row inserted
SQL> insert into TB_SingleNumberColumn(Col) values(5);
1 row inserted
SQL> insert into TB_SingleNumberColumn(Col) values(11);
1 row inserted
SQL> insert into TB_SingleNumberColumn(Col) values(111);
1 row inserted
SQL> commit;
Commit complete
-- The values as they are
SQL> select * from TB_SingleNumberColumn;
COL
----------
1
5
11
111
-- Values padded with zeros.
SQL> select to_char(col, '000') res
2 from TB_SingleNumberColumn;
RES
----
001
005
011
111
SQL> select lpad(to_char(col), 3, '0')
2 from TB_SingleNumberColumn
3 ;
LPAD(TO_CHAR(COL),3,'0')
------------------------
001
005
011
111
I saw something like the following in our production code:
select max(col_val) from table_name where
--set of conditions here
--AND
rownum=1;
This looked strange to me. Would the above code execute with the intended purpose?(selecting a max value from a set of values). Won't this select always return a single record from which the col_val would be chosen?. Thanks.
No. It is guarenteed to get the max of a set of values. It will return the first value only, where first value is driven by execution plan. Depending on the plan, the first value may be the max value also, but this could change because plans are not constant.
SQL> create table t (i number);
Table created.
SQL> insert into t values (1);
1 row created.
SQL> insert into t values (2);
1 row created.
SQL> select i from t;
I
----------
1
2
SQL> select max(i) from t;
MAX(I)
----------
2
SQL> select max(i) from t where rownum = 1;
MAX(I)
----------
1
SQL>
it will take the first row that satisfies conditions. max seems to be excess here.