This is the post regarding some problem with new line and tab in a oracle database table column
as the problem is that I have to create a column which
takes only keyboard symbols and alphanumerical values and i am able to get the
null value in the column but not able to get the new line ( ex chr(13),chr(9),chr(10), if i get one of this also, its difficult to get the combination of both)
I have used reg_exp (like and replace ) and also tanslate and repalce dint find any proper solution.
ex
create table Table1(someField varchar2(100) );
insert into Table1 values ( 'hi'|| CHR(10)||'how r u');
insert into Table1 values ( 'hello'|| CHR(13)||'&');
error must not come because we have a value that is
1) insert "hi
how r u"- successful .
2) insert "hello &"- successful .
but while inserting only space (chr(10)/chr(13)/chr(9) or space or tab)
error must come under below insert condition
insert into someTable values ( CHR(10));
insert into someTable values ( ' '|| CHR(10));
insert into someTable values ( '
'|| CHR(10)||' ');
One way could be by adding a check constraint to your table; for example:
alter table table1 add constraint table1Check check (
regexp_replace(somefield, '[' || chr(10) || chr(9) ||chr(13) || ' ]', '') is not null
)
What you have:
SQL> insert into Table1 values ( 'hi'|| CHR(10)||'how r u');
1 row created.
SQL> insert into Table1 values ( 'hello'|| CHR(13)||'&');
1 row created.
SQL> insert into Table1 values ( CHR(10));
insert into Table1 values ( CHR(10))
*
ERROR at line 1:
ORA-02290: check constraint (ALEK.TABLE1CHECK) violated
SQL> insert into Table1 values ( ' '|| CHR(10));
insert into Table1 values ( ' '|| CHR(10))
*
ERROR at line 1:
ORA-02290: check constraint (ALEK.TABLE1CHECK) violated
SQL> insert into Table1 values ( ' '|| CHR(10)||' ');
insert into Table1 values ( ' '|| CHR(10)||' ')
*
ERROR at line 1:
ORA-02290: check constraint (ALEK.TABLE1CHECK) violated
This way you will not be able to insert a value not matching your condition.
Related
Let's say we have a table like this:
CREATE TABLE test_table
(
text VARCHAR2(200) NOT NULL,
text2 VARCHAR2(200) NOT NULL,
ts TIMESTAMP
);
And we want to insert some data using INSERT ALL:
INSERT ALL
INTO test_table ( text, text2 ) VALUES ( 'test', 'test2' )
SELECT * FROM dual;
The result is
1 row inserted.
But, when we want to add trigger, to fill ts column with SYSTIMESTAMP
CREATE OR REPLACE TRIGGER test_trigger
BEFORE INSERT ON test_table
FOR EACH ROW
BEGIN
DBMS_OUTPUT.put_line('text=' || :new.text);
DBMS_OUTPUT.put_line('text2=' || :new.text2);
DBMS_OUTPUT.put_line('ts=' || :new.ts);
:new.ts := SYSTIMESTAMP;
END;
/
Running the same script
SET SERVEROUT ON;
INSERT ALL
INTO test_table ( text, text2 ) VALUES ( 'test', 'test2' )
SELECT * FROM dual;
The result is:
text=test
text2=
ts=
INSERT ALL
INTO test_table ( text, text2 ) VALUES ( 'test', 'test2' )
SELECT * FROM dual
Error report -
ORA-01400: cannot insert NULL into ("TEST"."TEST_TABLE"."TEXT2")
Using INSERT works fine
SET SERVEROUT ON;
INSERT INTO test_table ( text, text2 ) VALUES ( 'test', 'test2' )
The result is
text=test
text2=test2
ts=
1 row inserted.
Also this works:
INSERT ALL
INTO test_table ( text, text2, ts) VALUES ( 'test', 'test2', null )
SELECT * FROM dual
When I change ts column type to DATE works fine with this kind of trigger.
I'm using Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production, I've also checked on Oracle 12c but there is no error, so maybe it's some kind of bug in 11g release?
Nothing seems wrong with your code, it may be a bug with version you are using.
That said, what you are trying to achieve is more usually done by following create table statement
CREATE TABLE test_table (
text VARCHAR2(200) NOT NULL,
text2 VARCHAR2(200) NOT NULL,
ts TIMESTAMP not null default systimestamp
);
You will not need trigger for this at all.
I have the following table:
create table students
(
stuName varchar2(100),
cgpa number
);
My goal is to create a PL/SQL trigger that would fire if anyone tries to enter a name that contains any numeric values. My attempt:
create or replace trigger invalid_name
before insert
on students
for each row
declare
vName varchar2(100);
begin
vName := :new.stuName;
if upper(vName) like upper(vName) then
vName := initcap(vName);
end if;
exception
when value_error then
dbms_output.put_line('ERROR: Name contains numeric value(s).');
end;
I thought if the upper function were to act on a string containing any numeric value in it, it would throw an exception. But that's not happening and insert action is being executed.
I'd suggest using a constraint rather than a trigger.
create table foo (
name varchar2(100) NOT NULL
constraint name_non_numeric check ( not regexp_like( name, '[0-9]' ) )
);
Table created.
insert into foo ( name ) values ( 'Andy' );
1 row created.
> insert into foo ( name ) values ( 'Logan 5' );
insert into foo ( name ) values ( 'Logan 5' )
*
ERROR at line 1:
ORA-02290: check constraint (NAMESPACE.NAME_NON_NUMERIC) violated
If you don't want to replace, but check and raise an error, you can use this trick and raise an error if the result is not null:
SELECT LENGTH(TRIM(TRANSLATE('123b', ' +-.0123456789',' '))) FROM dual;
Result: 1
SELECT LENGTH(TRIM(TRANSLATE('a123b', ' +-.0123456789',' '))) FROM dual;
Result: 2
SELECT LENGTH(TRIM(TRANSLATE('1256.54', ' +-.0123456789',' '))) FROM dual;
Result: null
SELECT LENGTH(TRIM(TRANSLATE ('-56', ' +-.0123456789',' '))) FROM dual;
Result: null
Is there equivalent to this T-SQL query in PL/SQL (Oracle 12c)?
UPDATE A SET A.columnA = 10 WHERE A.columnB < 30 OUTPUT INSERTED.*, DELETED.*
The query updates table A and at the same time returns the status of the record before the update and after the update.
Trigger is not a solution for me as well as SELECT records before and SELECT records after updating.
Not a direct one, but using RETURNING INTO you will be able to achieve the same effect:
CREATE TABLE A(columnA VARCHAR2(10), columnB INT);
INSERT INTO A(columnA, columnB) VALUES ('Test', 10);
INSERT INTO A(columnA, columnB) VALUES ('Row 2', 20);
CREATE TABLE audit_table(col_new VARCHAR2(10),col_old VARCHAR2(10));
DECLARE
TYPE rec IS RECORD (actual A.columnA%TYPE, old A.columnA%TYPE);
TYPE col_a_t IS TABLE OF rec;
v_a col_a_t;
BEGIN
UPDATE (SELECT A.*, (SELECT A.columnA FROM dual) AS old_columnA FROM A)
SET columnA = 'XYZ'
WHERE columnB < 30
RETURNING columnA, old_columnA BULK COLLECT INTO v_a;
COMMIT;
-- printing for debug
FOR i IN v_a.first .. v_a.last LOOP
dbms_output.put_line('Old =>' || v_a(i).old || ' new => ' || v_a(i).actual);
END LOOP;
-- additional
FORALL i IN v_a.first .. v_a.last
INSERT INTO audit_table VALUES v_a(i);
COMMIT;
END;
/
SELECT * FROM A;
SELECT * FROM audit_table;
DBFiddle Demo
Idea taken from: Returning Old value during update
Here's my problem: I'm working inside a pl/sql package where I have a loop that compares the rule with table of users. I need to build a comma separated list of strings (#1) in which I can obtain invalid users (users that doesn't match the rule) and then create a sql query (#2) to exclude them from the rule.
1 Comma separated list:
Z=table that results after comparing the rule with main table of users
Below i am not sure if any of the two commented lines are good
declare user_list varchar2(4000)
IF Z IS NULL THEN
-- build the comma separated list
User_list:= --how to buil a list of strings?
END IF;
2 SQL statement:
--Using the created user_list, now just to exclude it from the main rule
IF USER_LIST IS NULL THEN
'SELECT * FROM RULE WHERE USER NOT IN (:USER_LIST)'
ELSE
RETURN RESULT_FROM_RULE;
END IF;
You can achieve your requirement using dynamic sql. See below how you can do it. I have put the comments inline for understading the code.
create table table1 (id number,
ColumnName varchar2(100))
create table table2 (Id number,
col1 varchar2(100),
col2 varchar2(100),
col3 varchar2(100));
Insert all
into TABLE1 (ID, COLUMNNAME) Values (1, 'col1')
into TABLE1 (ID, COLUMNNAME) Values (2, 'col2')
into TABLE2 (ID, col1, col2, col3) Values (1, 'RRR', 'KKK', 'MMM')
into TABLE2 (ID, col1, col2, col3) Values (2, 'ZZZ', 'PPP', 'QQQ')
into TABLE2 (ID, col1, col2, col3) Values (3, 'LLL', 'NNN', 'DDD')
select * from dual;
Code:
DECLARE
var VARCHAR2 (1000);
v_sql VARCHAR2 (2000);
TYPE x_var IS TABLE OF table2%rowtype ;
z_var x_var;
num number:=0;
BEGIN
FOR rec IN ( SELECT columnname
FROM table1
)
LOOP
num := num +1;
if num = 1 then
var:= rec.columnname;
else
var := var || ' , '|| rec.columnname;
end if;
END LOOP;
---This is how the comma seperated list is generated. This answers your query `**1 Comma separated list:**`
var := RTRIM (LTRIM (var, ','), ',');
--This is how you pass the string to your query . This answers your query `**2 SQL statement:**`
v_sql := 'select * from table2 where segment1 in ('|| var||')';
---This is how you execute your query.
EXECUTE IMMEDIATE v_sql BULK COLLECT INTO z_var;
--displaying the result of the query. If you are using a function you can return (z_var).
FOR i IN 1 .. z_var.COUNT
LOOP
DBMS_OUTPUT.put_line (z_var(i).Id ||','||z_var(i).col1);
END LOOP;
END;
Output:
SQL> /
1,RRR
2,ZZZ
3,LLL
PL/SQL procedure successfully completed.
Note: Please note that the you can use a single query suggested by GurV and simplify your job as well.
I created a trigger which works like when I update/insert a row in one table, an insert of a row will a done in another table which contains a primary key.
Now when I insert a row in the first table I want the trigger to check the last value of primary key of another table and if that is null or '-' then I've to insert 1 into that primary key column so as to insert the remaining values.
I've written the code as follows:
create or replace trigger "T1"
AFTER
insert or update on "buses"
for each row
begin
-- Here I want to check the V_id on vehicles table, if that is null or '-' then insert V_id as 1 along with the below insert statement.
if :NEW."b_key" is not null then
INSERT INTO vehicles (b_KEY,B_NAME,ADDRESS_1,CITY,STATE,ZIP,PHONE,WEBSITE) VALUES (:new.b_KEY,:new.b_NAME,:new.ADDRESS_1,:new.CITY,:new.STATE,:new.ZIP,:new.PHONE,:new.WEBSITE);
end if;
end;
How to find the last b_id in the vehicles table, so that if that value is null or '-' insert b_id as 1, followed by the above insert statement in the same row.
By adding another trigger we can do that as follows:
create or replace TRIGGER "B_VEHICLES"
before insert on "buses"
for each row
declare b_number number;
begin
select max(B_ID) into b_number from Vehicles;
if :OLD."B_ID" is null and b_number is null then
select 1 into :new."B_ID" from dual;
else select b_number + 1 into :new."B_ID" from dual;
end if;
end;