SQL: outer join two tables on String and insert similar into another - sql

I have two tables A and B with 30 columns (same variable names, data for different year), no primary key, almost a million records each.
I want to compare A.X1 with B.X1 (nvarchar8, contains spaces, -, letter and numbers) and insert the outer join results in another table C (with same 30 columns) so I have all rows of A and where B!=A on B.X1).
Example:
Table A
X1 X2 X3 ..... X30
11 E R ..... G
12 R 4 L
13 S 5 NULL
14 D T NULL
Table B
X1 X2 X3 ..... X30
11 E R ..... G
12 R 4 L
15 R2 56 NULL
16 R1 T1 NULL
Resulting table C
X1 X2 X3 ..... X30
11 E R ..... G
12 R 4 L
13 S 5 NULL
14 D T NULL
15 R2 56 NULL
16 R1 T1 NULL
How do I do that.
I tried
INSERT INTO C
SELECT *
from A
full outer join B
on A.X1 = B.X1
Error I get
Msg 213, Level 16, State 1, Line 1
Insert Error: Column name or number of supplied values does not match table definition.
I have C created, which is currently empty.

insert C
select *
from A
union all
select *
from B
where not exists
(
select *
from A
where X1 = B.X1
)

Your query will not work becasue you are joining the tables and retunring *, with ill results in twice the number of columns that you need.
What you really want to do is select everything from table A then APPEND (rather than join) all the records from table B.
Appends are achieved by using a UNION. Here is some sample code. Note: never, ever use SELECT *. Addapt the follwing to include the specifically named fields in the correct order.
Also, I am using UNION rather than UNION ALL so that the query automaticlly excludes the records in B that are duplicates of records in A.
SELECT FIELDS...
FROM TABLEA
UNION
SELECT SAME_FIELDS...
FROM TABLEB

Insert Into TableC
(
-- List your fields explicitly
)
Select
-- List all tableA.Fields explicitly
From tableA
Left Outer Join tableB On tableB.X1 = tableA.X1
Where tablB.X1 IS NULL

Related

Suppress rows with reverse/swapped values

I would like to query a database table that contains rows that have reverse values than other rows. So the table looks like this
Src Trgt ValueA ValueB
A B 1,44 5
B A 1,44 5 <--
C D 1,23 8
D C 1,23 8 <--
F G 5,12 9
G F 5,12 9 <--
What I want is a query that returns all rows that do not again with the source and target value swapped. The rows that should not be queried are the ones that have the same Value A and B like another row, but only with source and target value swapped (The ones marked in above table)
So, the desired results would look like this:
Src Trgt ValueA ValueB
A B 1,44 5
C D 1,23 8
F G 5,12 9
I think this is what you want:
select t.*
from t
where t.src < t.trgt
union all
select t.*
from t
where t.src > t.trgt and
not exists (select 1
from t t2
where t2.src = t.trgt and t2.trgt = t.src and
t2.a = t.a and t2.b = t.b
);
It keeps the first row encountered, filtering out equivalent rows where the first two columns are switched.
EDIT:
Another approach if you just one one row per combo is:
select least(src, trgt) as src, greatest(src, trgt) as trgt, a, b
from t
group by least(src, trgt), greatest(src, trgt), a, b;
This runs the risk of returning a row not in the original data (if the row has no duplicate and trgt > src.
SELECT *
FROM ztable zt
WHERE zt.source < zt.target -- pick only one of the twins
OR NOT EXISTS( -- OR :if it is NOT part of a twin
SELECT *
FROM ztable nx
WHERE nx.source = zt.target
AND nx.target = zt.source
);
Assuming that rows with source=target are not present or not wanted.

Find differences between two large tables in oracle

I have two different tables, say table A and B in oracle with around 15 million records in each. Table A has columns (a,b,c,d) and
Table B has columns (e,f,g,h).
The objective is to write a stored procedure to check if every record present in table A is also present in table B and vice versa. Differences between these two should be inserted into a third table.
My problem is that
column a in Table A should be compared with concatenate of column e and f in table B if column e contains a certain string (0311),
if not I have to compare it with just column f.
Column b should be compared with column g in table B and
I also have to compare column c in the table A with column g in table B, if the two aren't a match column d should be compared with column g.
What's the fastest way to do so?
for example these two are a match:
Table A: 9353456789,03117884657,12082200003035,12082123595535
Table B: 9353456789,0311,7884657,12082200003035
or:
Table A: 9353456789,03117884657,12082200003035,12082123595535
Table B: 9353456789,0311,7884657,12082123595535
example of records that do not need concatenation and are a match:
Table A: 9353456789,03617884657,12082200003035,12082123595535
Table B: 9353456789,0361,03617884657,12082200003035
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TableA ( a VARCHAR2(20), b VARCHAR2(20), c VARCHAR2(20), d VARCHAR2(20) );
CREATE TABLE TableB ( e VARCHAR2(20), f VARCHAR2(20), g VARCHAR2(20), h VARCHAR2(20) );
CREATE TABLE TableC ( i VARCHAR2(20), j VARCHAR2(20), k VARCHAR2(20), l VARCHAR2(20) );
INSERT INTO TableA
SELECT '9353456789','03117884657','12082200003035','12082123595535' FROM DUAL
UNION ALL SELECT '9353456789','03617884657','12082200003035','12082123595535' FROM DUAL
UNION ALL SELECT '9353456789','03617884657','12082200003034','12082123595534' FROM DUAL;
INSERT INTO TableB
SELECT '9353456789','0311','7884657','12082200003035' FROM DUAL
UNION ALL SELECT '9353456789','0311','7884657','12082123595535' FROM DUAL
UNION ALL SELECT '9353456789','0361','03617884657','12082200003035' FROM DUAL
UNION ALL SELECT '9353456789','0361','03617884657','12082200003036' FROM DUAL;
Query 1:
To insert the rows - perform an INSERT INTO... SELECT using a FULL OUTER JOIN between both tables using your requirements as the join condition; then for the rows which do not match either TableA(a, b, c, d) will all be NULL or TableB(e, f, g, h) will all be NULL and this can be used in the WHERE condition to only get the non-matched rows. Finally, so as not to return NULL values, COALESCE() is used for the returned values.
INSERT INTO TableC
SELECT COALESCE( ta.a, tb.e ) AS i,
COALESCE( ta.b, tb.f ) AS j,
COALESCE( ta.c, tb.g ) AS k,
COALESCE( ta.d, tb.h ) AS l
FROM TableA ta
FULL OUTER JOIN
TableB tb
ON ( ta.a = tb.e
AND ta.b = CASE tb.f WHEN '0311' THEN tb.f || tb.g ELSE tb.g END
AND ( ta.c = tb.h OR ta.d = tb.h )
)
WHERE ta.a IS NULL
OR tb.e IS NULL;
Query 2:
SELECT * FROM TableC
Results:
| I | J | K | L |
|------------|-------------|----------------|----------------|
| 9353456789 | 03617884657 | 12082200003034 | 12082123595534 |
| 9353456789 | 0361 | 03617884657 | 12082200003036 |
I'd do this as two statements, though it can be combined
Select a.*
from tablea a left join tableb b on a.a =
case when e = 'string' then b.e || b.f else b.f end
and ...
where b.e is null
The left join will return nulls where a row isn't found in table b, so this should bring up a list of rows i9n table a not in table b. Change the statement to a right join and select b.* and you'll see whats in b but not in a.
Statement can be turned into a 'create table as' which will create a new table with the results from this select statement.
I put and ... your conditions there are a bit confusing, you'll just need to use case statements to pick which columns you want to compare/join on.

Union all and merge in sql

Here is what I needed:
I have:
Table A PT*,NAME,AGE
Table B PT*,COURSE,RESULT
Table C PT*,COURSE,RESULT,RANk
Wondering how could I UNION Table B and Table C and later Merge with Table A to get the output as below(Table D). PT is the PKey among all.
PT NAME AGE COURSE RESULT RANK
100 SLK 29 Test1 29 - result of merge between Table A and Table B
200 AAR 30 Test2 23 10 - result of merge between Table A and Table C
To get desirable output just perform a simple SQL SELECT query:
SELECT A.PT, A.NAME, A.AGE, B.COURSE, B.RESULT, C.RANK
FROM
A join B on A.PT=B.PT
join C ON A.PT = C.PT
Why you need COURSE, RESULT fields in table C, by the way, as they are already stored in table B?

SQL Multiple Tables

I have 2 sets of 2 corresponding tables (4 tables total). The two sets only correspond in one column. I want the query to search through that one column in both joined tables, and be able to return the value in the selected column, even if that column doesn't exist in the other table.
Currently, my query looks like:
select z
FROM A1
INNER JOIN A2
ON A1.x=A2.x
WHERE A1.x= '25'
UNION
select z
FROM B1
INNER JOIN B2
ON B1.x=B2.x
WHERE B1.x= '25'
UNION works as long as I am looking for a column which both (joined) tables A and B have in common. I'd like to be able to get values from columns which only exist in A or in B, but not necessarily both of them.
Thanks in advance.
Edit:
Basically, I want two completely separate queries on separate tables, but in one query, with only one select.
Example:
Table A1
x | y
------
1 | a
2 | b
Table A2
x | z
------
1 | c
2 | d
Table B1
x | v
------
3 | e
4 | f
Table B2
x | w
------
3 | g
4 | h
So I want look for a column variable (such as v,w,y, or z), with a specified value of x. e.g. select w where x=4 should give me h; select z where x=2 should give me d.
You must have the same number of columns in each select statement when using UNION. You can add constant values for columns that are missing. You must also have the same data type for each column.
select Column1, null as Column2
from T1
union
select '', Column2
from T2
As per comment by #Adrian, you can of course use null as a constant value. Otherwise you need to pick a constant value of the data type that is used for the column.
select Column1, null as Column2
from T1
union
select null, Column2
from T2
Use the sample data provided in the question:
select A1.x, A2.z as 'y'
from A1
inner join A2
on A1.x=A2.x
where A1.x= 4
union
select B1.x, B2.w as 'y'
from B1
inner join B2
on B1.x=B2.x
where B1.x= 4
Result:
x y
4 h
With a 2 instead of a 4
Result:
x y
2 d
It would be something like that:
select Column1, ColumnThatOnlyExistsInContextA, null as ColumnThatOnlyExistsInContextB
FROM A1
INNER JOIN A2
ON A1.ID=A2.ID
WHERE A1.ID= '25'
UNION
select Column1, null, ColumnThatOnlyExistsInContextB
FROM B1
INNER JOIN B2
ON B1.ID=B2.ID
WHERE B1.ID= '25'
When using UNION, make sure all queries return result sets that have the same number of columns with the same type. If you want to return a column from the second query in a union that the first query doesn't have, you can modify your first query to have a NULL value for that column.
So you basically want to do:
select Column1
FROM A1
INNER JOIN A2
ON A1.ID=A2.ID
WHERE A1.ID= '25'
UNION
select Column2
FROM B1
INNER JOIN B2
ON B1.ID=B2.ID
WHERE B1.ID= '25'
right?
If so, your problem is probably just that Column1 and Column2 are different types. So, do something like
select cast(Column1 as varchar(255))
and
select cast(Column2 as varchar(255))
Should work!
Well, UNION's only requirement is that the number and type of the fields in each result set being UNIONed must match. So, if B has a Column2 and A doesn't, you can select Column1 from the joined As and Column2 from the joined Bs, and provided A.Column1 and B.Column2 are the same type (you can CAST or CONVERT if necessary) the statement will still work. Maybe I'm not understanding the problem, but I think it's pretty easy to solve.

Multiple NOT distinct

I've got an MS access database and I would need to create an SQL query that allows me to select all the not distinct entries in one column while still keeping all the values.
In this case more than ever an example is worth thousands of words:
Table:
A B C
1 x q
2 y w
3 y e
4 z r
5 z t
6 z y
SQL magic
Result:
B C
y w
y e
z r
z t
z y
Basically it removes all unique values of column B but keeps the multiple rows of the
data kept. I can "group by b" and then "count>1" to get the not distinct but the result will only list one row of B not the 2 or more that I need.
Any help?
Thanks.
Select B, C
From Table
Where B In
(Select B From Table
Group By B
Having Count(*) > 1)
Another way of returning the results you want would be this:
select *
from
my_table
where
B in
(select B from my_table group by B having count(*) > 1)
select
*
from
my_table t1,
my_table t2
where
t1.B = t2.B
and
t1.C != t2.C
-- apparently you need to use <> instead of != in Access
-- Thanks, Dave!
Something like that?
join the unique values of B you determined with group by b and count > 1 back to the original table to retrieve the C values from the table.