Im trying to insert a record into my table. But there is 1 column in which I want to get concatenated results of 2 select statements. Like the 2 statements will fetch their records and concatenate to form 1 value so that it can be inserted into the column.
insert into ABC (Name,City,Age)
Values ('John',(
(Select City from TableA where ID=1)concat(Select City from TableA where ID=2)),'22')
Or it can be comma separated but I am not getting what to use here.
Try this one:
INSERT INTO ABC (Name, City, Age)
VALUES ('John',
(
(SELECT City FROM TableA WHERE ID = 1) ||
(SELECT City FROM TableA WHERE ID = 2)
),
'22');
But ensure ... WHERE ID = 1 and ....WHERE ID = 2 return one row.
Using a cross join to select from the two tables produces a nice clear statement:
insert into ABC (Name,City,Age)
select 'John', concat(t1.city, t2.city), 22
from TableA t1
cross join TableA t2
where t1.ID = 1
and t2.ID = 2
/
Use CONCAT() or CONCAT_WS() functions for this (reference)
insert into ABC (Name,City,Age) Values (
'John',
CONCAT_WS(' ', (Select City from TableA where ID=1), (Select City from TableA where ID=2)),
'22'
)
Related
As the title says, I am looking for a way to remove all rows from TableA where there is a matching row in TableB.
the Tables A & B have about 30 columns in them so a WHERE A.col1 = B.col1 etc would be a little problematical. Ideally I was hoping for something like
DELETE FROM tableA WHERE IN TableB
(overly simplified by this type of thing)
IN clause can compare all columns returned from select
DELETE FROM tableA WHERE ( col1,col2,col3,.. ) IN ( select col1,col2,col3... FROM TableB );
The brute force way to establish if two records from each table are the same is to just compare every column:
DELETE
FROM tableA a
WHERE EXISTS (SELECT 1 FROM tableB b WHERE a.col1 = b.col1 AND a.col2 = b.col2 AND ...
a.col30 = b.col30);
You could create function which checks structures of tables and, if they are the same, creates string containing correct conditions to compare.
For example here are two tables:
create table t1 (id, name, age) as (
select 1, 'Tom', 67 from dual union all
select 2, 'Tia', 42 from dual union all
select 3, 'Bob', 16 from dual );
create table t2 (id, name, age) as (
select 1, 'Tom', 51 from dual union all
select 3, 'Bob', 16 from dual );
Now use function:
select generate_condition('T1', 'T2') from dual;
result:
T1.ID = T2.ID and T1.NAME = T2.NAME and T1.AGE = T2.AGE
Copy this, paste and run delete query:
delete from t1 where exists (select 1 from t2 where <<PASTE_HERE>>)
Here is the function, adjust it if needed. I used user_tab_columns so if tables are on different schemas you need all_tab_columns and compare owners too. If you have Oracle 11g you can replace loop with listagg(). Second table has to contain all columns of first table and they have to be same type and length.
create or replace function generate_condition(i_t1 in varchar2, i_t2 in varchar2)
return varchar2 is
v varchar2(1000) := '';
begin
for rec in (select column_name, u2.column_id
from user_tab_cols u1
left join (select * from user_tab_cols where table_name = i_t2) u2
using (column_name, data_type, data_length)
where u1.table_name = i_t1 order by u1.column_id)
loop
if rec.column_id is null then
v := 'ERR: incompatible structures';
goto end_loop;
end if;
v := v||' and '||i_t1||'.'||rec.column_name
||' = '||i_t2||'.'||rec.column_name;
end loop;
<< end_loop >>
return(ltrim(v, ' and '));
end;
If you want to avoid running process manually you need dynamic PL/SQL.
create table tableA (a NUMBER, b VARCHAR2(5), c INTEGER);
create table tableB (a NUMBER, b VARCHAR2(5), c INTEGER);
As you said
WHERE A.col1 = B.col1 etc would be a little problematical
you could intersect the tables and mention all columns from tableA one time, like this:
delete tableA
where (a,b,c) in (select * from tableA
intersect
select * from tableB);
I have two tables, Table A has an ID and an Event Date and Table B has an ID, a Description and an Event Date.
Not all IDs in Table A appear in Table B and some IDs appear multiple times in Table B with different Descriptions for each event.
The Description in Table B is an attribute that can change over time, the Event date in Table B is the date that a given ID's Description changes from its default value (kept in another table) to the new value.
I want to find the Description in Table B that matches the Event Date in Table A so, for example
Table Sample Data
A1234 would return Green and A4567 would return Null
I can't create tables here so I need to be able to this with a query.
This query will select last description from before the event:
SELECT * FROM (
SELECT tabA.id, tabA.event_date, tabB.description,
ROW_NUMBER() OVER(PARTITION BY tabB.id ORDER BY tabB.event_date DESC) rn
FROM Table_A tabA
LEFT JOIN Table_B tabB ON tabA.id = tabB.id AND tabB.event_date <= tabA.event_date
) WHERE rn = 1
If I understand well your need, this could be a way:
select a.id, description
from tableA A
left join
(select id,
description,
event_date from_date,
lead(event_date) over (partition by id order by event_date) -1 as to_date
from tableB
) B
on (A.id = B.id and a.event_date between b.from_date and b.to_date)
The idea here is to evaluate, for each row in tableB the range of dates for which that row, and its description, is valid; given this, a simple join should do the job.
You can left join tables like:
select a.ID , b1.DESCRIPTION
from TABLE_A a
left join TABLE_B b1 on a.ID = b1.id and a.EVENT_DATE > b1.EVENT_DATE
left join TABLE_B b2 on a.ID = b2.id and b1.EVENT_DATE < b2.EVENT_DATE and a.EVENT_DATE > b2.EVENT_DATE
where b1.id is null or b2.EVENT_DATE is null;
I've got a table as follows
Table1
ID Name Tag
-----------------
1 N1 2.1
2 N2 3.5
3 N1 3.5
4 N3 8.1
I create a new table Table2 with ID and Name (unique constraint) and I want to insert Table1's contents into Table2 avoiding duplicates, in the sense that I want only 1, 2 and 4 from Table1 in Table2.
I've tried this but it doesn't seem to work and I get the unique constraint error (ORACLE SQL)
INSERT INTO TABLE2 (ID, NAME)
SELECT ID, NAME
FROM TABLE1
WHERE NAME NOT IN (SELECT NAME FROM TABLE2);
Please can someone point me in the right direction?
Sorry for not making myself clear. Table2 is a brand new table. I want the first values inserted, the following duplicates should be ignored. So in my case, N1, N2 get inserted, N1 is dupe so it is ignored, N3 is inserted
OK - from your description, I understand table t2 is currently empty, and you want to copy the rows where id is in (1, 2, 4) from table t1 to table t2.
Why your code fails:
You seem to believe that the condition is applied to the first row in t1, it passes so it is inserted into t2, then the condition is applied to the second row in t1 (using what is already inserted in t2), etc. - and you don't understand why there is any attempt to insert ALL the rows from t1 into t2. Why doesn't the third row fail the WHERE clause?
Good question! The reason is that operations are done on a SET basis. The WHERE condition uses table t2 AS IT WAS before the INSERT operation began. So for ALL rows, the WHERE clause compares to an empty table t2.
How to fix this... Decide which id you want to add when there are duplicate names. For example, one way to get the result you said you wanted is to select MIN(id) for each name. Moreover, you still want to check if the name exists in t2 already (since you may do this again in the future, when t2 is already partially populated).
insert into t2 ( id, name )
select min(id), name
from t1
where name not in (select name from t2)
group by name
;
You can try it bother....!
Insert into tb2(Field1, Field2)
SELECT Field1, Field2
FROM tb1
WHERE NOT EXISTS (SELECT Field1 FROM tb1) ;
This is how I understood the question:
SQL> create table table2
2 (id number,
3 name varchar2(2),
4 tag number,
5 constraint pk_t2 primary key (id, name)
6 );
Table created.
SQL>
SQL> insert into table2 (id, name, tag)
2 with test (id, name, tag) as
3 (select 1, 'N1', 2.1 from dual union
4 select 2, 'N2', 3.5 from dual union
5 select 3, 'N1', 3.5 from dual union
6 select 4, 'N3', 8.1 from dual
7 )
8 select min(id), name, max(tag)
9 from test
10 group by name;
3 rows created.
SQL>
SQL> select * from table2 order by id;
ID NA TAG
---------- -- ----------
1 N1 3,5
2 N2 3,5
4 N3 8,1
SQL>
When we need to unique any two or more column we have to create unique index.
Run this query
ALTER TABLE TABLE2 ADD UNIQUE unique_index( id, name);
and then
INSERT INTO TABLE2 (id,name,tag) VALUES(1, "N1", 3.5 )
ON DUPLICATE KEY UPDATE tag=3.5
this will also help to update new tag
Try to check if the id and name from Table1 is doesn't exist in Table2, if then insert.
If the unique constraint on TABLE2 is a composite key then run this:
INSERT INTO TABLE2 (ID, NAME)
SELECT A.ID, A.NAME
FROM TABLE1 A
WHERE NOT EXISTS (SELECT NULL FROM TABLE2 B WHERE A.ID=B.ID AND A.NAME=B.NAME);
If there are two unique constraints; one on the id, and the other on the name then run this instead:
INSERT INTO TABLE2 (ID, NAME)
SELECT A.ID, A.NAME
FROM TABLE1 A
WHERE NOT EXISTS (SELECT NULL FROM TABLE2 B WHERE A.ID=B.ID OR A.NAME=B.NAME);
ORACLE, in case you need to get values from 2 different tables.
below example,i use an increment case.
INSERT INTO TABLE1
(INDEX, REMARKS, NAME, AGE)
(SELECT (SELECT colescs(MAX(INDEX),0) FROM TABLE1)+1,
'any remarks',
t2.NAME, t2,age from TABLE2 t2 where t2.name = 'apple')
explanation
match below numbers (1)-(1), (2)-(2) ...
INSERT INTO TABLE1
(INDEX, //index increment (1)
REMARKS, //hard code (2)
NAME, //from table2 (3)
AGE) //from table2 (4)
(SELECT // this part is to get values from another table
(SELECT colescs(MAX(INDEX),0) FROM TABLE1)+1, //increment (1)
'any remarks', //hard code value (2)
t2.NAME, //from table2 (3)
t2,age //from table2 (4)
from TABLE2 t2 where t2.name = 'apple') //condition for table2
I have 2 tables
Table 1:
#######
ID Location
1 India
2 Australia
Table 2:
############
Name Locations
test1 India|North America
test2 Indiana|Australia
I used the below query to get the Name from table 2 if it contains Location in Locations of table 2.
select Name
from table2 t2 inner join table1 t1
on instr(t1.Location,t2.Locations,length(t1.Location)) >= 1;
But when executed it still gives me results for Indiana as well whereas it should just return me result for location India alone.
I tried using contains in query too, but contains takes second parameter as string but not as column name.
Is there any other approach on this?
regexps always help in such cases
with
table1 (id, location) as (
select 1, 'India' from dual union
select 2, 'Australia' from dual
),
table2 (name, locations) as (
select 'test1', 'India|North America' from dual union
select 'test2', 'Indiana|Australia' from dual
)
select *
from table2 join table1 on
regexp_like (locations, '(^|\|)' || location || '(\||$)')
Try to look up location with delimiter, like this:
select Name from table2 t2
inner join table1 t1 on instr(t2.Locations,t1.Location||'|') >= 1
I am new to Oracle technology. Earlier I posted 2 posts for the same issue due to lack of understanding the requirement.
Table 1:
MSGID
-----
1,2,3
2,3
4
null
null
Table 2:
MID MSGDESC
---- -------
1 ONE
2 TWO
3 THREE
4 FOUR
Expected output:
XCOL DESC
----- -----
1,2,3 ONE,TWO,THREE
2,3 TWO,THREE
4 FOUR
I am not able to fulfil this requirement. Please provide me one solution.
Note: tables don't have any unique or primary key values. Table 1 has 5000 records and table 2 only has 80 records with descriptions.
create table Table1 (MSGID varchar2(100));
insert into Table1 values ('1,2,3');
insert into Table1 values ('2,3');
insert into Table1 values ('4');
insert into Table1 values (null);
insert into Table1 values (null);
create table Table2 (MID varchar2(100), MSGDESC varchar2(100));
insert into Table2 values ('1','ONE');
insert into Table2 values ('2','TWO');
insert into Table2 values ('3','THREE');
insert into Table2 values ('4','FOUR');
select
msgid as xcol,
"DESC",
col1, col2, ..., col12
from
Table1
left join (
select
msgid,
wm_concat(msgdesc) as "DESC"
from
(
select
msgid,
msgdesc
from
(select distinct msgid from Table1 where ...)
cross join (
select level as occ from dual connect by level <= 100)
)
left join Table2
on mid = regexp_substr(msgid, '[^,]+', 1, occ)
where
occ <= regexp_count(msgid, ',') + 1
order by msgid, occ
)
group by msgid
) using (msgid)