If I have the following;
SQL> create table test (field1 varchar(25));
Table created.
SQL> insert into test values ('Ric''s test');
1 row created.
SQL> select * from test;
FIELD1
-------------------------
Ric's test
How can I change the select statement so that the result is,
Ric''s test
so the ' is escaped
Long version, I am writing a statement that will extract the table into sql statements, for example;
create table test2 (field1 varchar(25),
field2 varchar(25),
field3 varchar(25),
field4 varchar(25),
field5 varchar(25)
);
insert into test2 values ('one','two','three''s','four','five');
select 'INSERT INTO othertable (
field1,field2,field3,field4,field5) values
('''||field1||''', '''||field2||''', '''||field3||''',
'''||field4||''', '''||field5||''');' as val from test2;
The result of the last select is;
INSERT INTO othertable (
field1,field2,field3,field4,field5) values
('one', 'two', 'three's',
'four', 'five');
which is redirected into a .sql file, which can then be run later.
However, as you can see the 'three's' is incorrect, and i need to escape it.
Any suggestions really appreciated.
select replace(field1, '''', '''''') from test
You can use the Q quote syntax:
SQL> insert into test values (q'[Ric''s test]');
1 row created.
SQL> select * from test;
FIELD1
-------------------------
Ric''s test
This wil say to Oracle to interpret the string exactly as is; I used [], but you can use quite anything you want: [], {}, <>, ...
Related
Let´s say I create this table:
CREATE TABLE MYTABLE (
id INT NOT NULL AUTO_INCREMENT,
Field1 VARCHAR(30),
Field2 NUMBER(10),
);
Then I will insert this values:
INSERT INTO MYTABLE VALUES(null, 'Value', 10);
What I want is to be able to do both of these inserts:
INSERT INTO MYTABLE VALUES(null, 'Value', 5);
/* This works as there isn´t a row with both Field1='Value' and Field2=5 at the same time */
INSERT INTO MYTABLE VALUES(null, 'Something', 10);
/* This works as there isn´t a row with both Field1='Something' and Field2=10 at the same time */
But I don´t want to be able to do this (repeat both the Field1 and Field2 values together):
INSERT INTO MYTABLE VALUES(null, 'Value', 10);
/* This doesn´t work as there is a row with both Field1='Value' and Field2=10 at the same time */
How can I achieve this behaviour in Oracle? I thought about using ASSERTIONS but they are not yet implemented in Oracle.
I don´t want to be able to do this (repeat both the Field1 and Field2 values together)
You can use a COMPOUND trigger:
CREATE OR REPLACE TRIGGER mytable__not_repeat_f1_and_f2
FOR UPDATE OR INSERT ON MyTable
COMPOUND TRIGGER
TYPE MyTable_Fields_Type IS RECORD(
rid ROWID,
field1 MyTable.Field1%TYPE,
field2 MyTable.Field2%TYPE
);
TYPE MyTable_Fields_Table_Type IS TABLE OF MyTable_Fields_Type;
fields MyTable_Fields_Table_Type := MyTable_Fields_Table_Type();
AFTER EACH ROW IS
BEGIN
fields.EXTEND;
fields(fields.COUNT) := MyTable_Fields_Type(
:NEW.ROWID,
:NEW.Field1,
:NEW.Field2
);
END AFTER EACH ROW;
AFTER STATEMENT IS
num_field1 PLS_INTEGER;
num_field2 PLS_INTEGER;
BEGIN
FOR i IN 1 .. fields.COUNT LOOP
SELECT COUNT( CASE WHEN Field1 = fields(i).Field1 THEN 1 END ),
COUNT( CASE WHEN Field2 = fields(i).Field2 THEN 1 END )
INTO num_field1,
num_field2
FROM MyTable
WHERE ROWID != fields(i).RID;
IF num_field1 > 0 AND num_field2 > 0 THEN
RAISE_APPLICATION_ERROR( -20000, 'Cannot have duplicate Field1 and Field2' );
END IF;
END LOOP;
END AFTER STATEMENT;
END;
/
Then, for the table:
CREATE TABLE MYTABLE (
id INT
GENERATED ALWAYS AS IDENTITY
PRIMARY KEY,
Field1 VARCHAR2(30),
Field2 NUMBER(10)
);
If you do:
INSERT INTO MyTable ( Field1, Field2 )
SELECT 'a', 1 FROM DUAL UNION ALL
SELECT 'b', 2 FROM DUAL UNION ALL
SELECT 'c', 3 FROM DUAL;
That works but then trying to do:
INSERT INTO MyTable ( Field1, Field2 ) VALUES ( 'b', 3 );
Would raise the exception:
ORA-20000: Cannot have duplicate Field1 and Field2
ORA-06512: at "SCHEMA_NAME.MYTABLE__NOT_REPEAT_F1_AND_F2", line 33
ORA-04088: error during execution of trigger 'SCHEMA_NAME.MYTABLE__NOT_REPEAT_F1_AND_F2'
But:
INSERT INTO MyTable ( Field1, Field2 ) VALUES ( 'b', 4 );
Would work since this doesn't repeat a Field1 and a Field2 value together.
db<>fiddle here
If you want each column to be unique, you can just use unique constraints:
CREATE TABLE MYTABLE (
id INT NOT NULL AUTO_INCREMENT,
Field1 VARCHAR(30) UNIQUE,
Field2 NUMBER(10) UNIQUE
);
Create a compound unique index containing both columns so that the combination can't be inserted more than once, whether it be at the same time or at different times.
I don't think there's any way to do this reliably. If I understand correctly, you want to reject an inserted row if Field1 and Field2 both already exist in the table, but not necessarily in the same row.
So if your table looks like:
Field1 Field2
------ ------
Value 5
Something 10
I should be able to insert ('Apple', 7), right? Then when i try to insert ('Value', 7), it fails because there are rows with both those values already.
But I could do them in the reverse order: insert ('Value', 7) and then ('Apple', 7)
So what happens if I do this?
WITH mydata AS (
SELECT 'Apple' AS field1, 7 AS field2 FROM dual UNION ALL
SELECT 'Value', 7 FROM dual
INSERT INTO mytable
SELECT null, field1, field2 FROM mydata
Does that succeed or fail? There's no way to know. You are not guaranteed that the database actions happen in the order in which you think they're going to happen.
You'll run into the same problem if two sessions try to insert these two rows, then commit.
I am creating a virtual column in a SQL Server query named TempField.
I would like each value in the virtual column to have the same value as the field1 column PLUS append a _suffix string (which is constant/same for all values).
Said another way, the XXX represents a string from field1 and _suffix is a string that I would like to append to XXX (the appended string is the same for all values).
SELECT field1, field2, 'XXX_suffix' as TempField
FROM table1
declare #temp as table (FName varchar(100) , LName varchar(100), Email varchar(100) )
insert into #temp (FName,LName,Email) values ('A','B','C')
insert into #temp (FName,LName,Email) values ('A1','B1','C1')
insert into #temp (FName,LName,Email) values ('A2','B2','C2')
insert into #temp (FName,LName,Email) values ('A','B','C')
insert into #temp (FName,LName,Email) values ('A1','B1','C1')
insert into #temp (FName,LName,Email) values ('A1','B1','C2')
select FName,LName,Email, (FName +'_suffix') as NewColumn
from #temp
If you mean a computed column, then this will do that for you:
create table test(
column1 varchar(20),
column2 as column1 + '_suffix' -- this is calculated when needed and not stored
);
insert test (column1) values ('adam'),('burt');
select * from test;
-- result:
column1 column2
------- -----------
adam adam_suffix
burt burt_suffix
I have a bit of different scenario. there is one column (Oracle table) in the table which stores patterns.another column with unique id.
Now, i have to match those patterns against a string and have to find out which patterns are matching that string.then i have to pick out those matched patterns along with the ids
Can anybody guide me on how to efficiently do it?
Sample Data
Table 1
-------
Column1 Column2
1 AB%
2 A%
3 %c%
Now, there is a string comes like ABC (take it as an item number. It gets inserted in DB and then a trigger fires that has to do the rest of the job as provided in sample below)
Table 2
---------
Column1 Column2
ABC AB%,A%
or more efficient(desired) Table 2 would be like -
Table 2(desired)
---------
Column1 Column2
ABC 1,2
This is the desired result.
In Oracle 11g you could use function listagg
and simple before insert or update trigger:
Sample data:
create table table1 (column1 number(3), column2 varchar2(10));
insert into table1 values (1, 'AB%');
insert into table1 values (2, 'A%');
insert into table1 values (3, '%c%');
create table table2 (column1 varchar2(10), column2 varchar2(500));
Trigger:
create or replace trigger tg_table2_ins
before insert or update of column1 on table2 for each row
declare
v_list table2.column2%type;
begin
select listagg(t1.column1, ', ') within group (order by t1.column1)
into v_list from table1 t1
where :new.column1 like t1.column2;
:new.column2 := v_list;
end tg_table2_ins;
Test:
insert into table2 (column1) values ('ABC');
insert into table2 (column1) values ('Oracle');
insert into table2 (column1) values ('XYZ');
insert into table2 (column1) values ('Ascii');
select * from table2;
COLUMN1 COLUMN2
---------- ----------
ABC 1, 2
Oracle 3
XYZ
Ascii 2, 3
I created a new DB "TEST", add a new table "tblTest" and 1 column "Name" in it.
Insert some records: Minh, Tinh, Justin
create database TEST
go
use test
go
create table tblTest (Name varchar(50))
go
insert tblTest values ('Minh')
insert tblTest values ('Tinh')
insert tblTest values ('Justin')
Then I run this query
Select * from tblTest where Name like '%in%'
The result is: Justin. (Minh and Tinh are not display)
Anyone can tell me how to fix this?
Check this example, its give me your result as you want. First % is used for preceed and Last % used for succeeded.
declare #t table (name varchar(50))
insert into #t values('Minh'),('Tinh'),('Justin')
Select * from #t where Name like '%in%'
Result will be
name
Minh
Tinh
Justin
See if this query is working and providing the necessary output.
with tblTest as
(
Select 'Minh' name from dual union
Select 'Tinh' name from dual union
Select 'Justin' name from dual
)
Select * from tblTest where Name like '%in%'
Else, delete all records from tblTest using:
DELETE from tblTest;
Then, insert records using:
INSERT INTO TBLTEST (NAME) VALUES ('Minh');
INSERT INTO TBLTEST (NAME) VALUES ('Tinh');
INSERT INTO TBLTEST (NAME) VALUES ('Justin');
Now try executing your SELECT query again.
As #podiluska pointed out, there could be some foreign junk characters.
Is there a way, in Oracle 11gR2 that I could create a single column with two names?
Reason I need this is back compatibility, on situations in which this would work:
create table test1 (col1 varchar2(10), col2 [some ref to col1]);
insert into test1 values ('test_value');
and then
SQL> select col1 from test1;
test_value
SQL> select col2 from test1;
test_value
There seem to be a way of thing so on SQL Server, I am looking for the Oracle equivalent to it.
ideas?
You can create a VIRTUAL COLUMN:
CREATE TABLE test1 (
col1 VARCHAR2(10),
col2 VARCHAR2(10) GENERATED ALWAYS AS (col1 || '')
);
INSERT INTO test1 (col1) VALUES ('test_value');
COMMIT;
SELECT * FROM test1;
COL1 COL2
---------- ----------
test_value test_value
However, virtual columns cannot be manipulated by DML. Read more here: Oracle Base - Virtual Columns