SQL to get the common rows from two tables - sql

I have two tables T1 and T2.
Can any one please help with a SQL query which will fetch the common rows from these two tables? (Assume T1 and T2 has 100 columns each)
P.S : I guess INNER JOIN on each of the columns will not be a good idea.
Thanks

If you are using SQL Server 2005, then you can use Intersect Key word, which gives you common records.
SELECT column1
FROM table1
INTERSECT
SELECT column1
FROM table2
If you want in the output both column1 and column2 from table1 which has common columns1 in both tables.
SELECT column1, column2
FROM table1
WHERE column1 IN
(
SELECT column1
FROM table1
INTERSECT
SELECT column1
FROM table2
)

Use INTERSECT
SELECT * FROM T1
INTERSECT
SELECT * FROM T2

Yes, INNER JOIN will work.
eg. SELECT (column_1, column_2, ... column_n) FROM T1 JOIN T2 ON (condition) WHERE (condition)
This query will fetch the common records (intersection of) in both the tables according to ON condition.

select
t1.*
from
t1, t2
where
(
(t1.col1 is null and t2.col1 is null) or (
(t1.col1 = t2.col1 )
) and
(
(t1.col2 is null and t2.col2 is null) or (
(t1.col2 = t2.col2 )
) and
(
(t1.col3 is null and t2.col3 is null) or (
(t1.col3 = t2.col3 )
) and
....
(
(t1.col100 is null and t2.col100 is null) or (
(t1.col100 = t2.col100 )
)

SELECT NAME FROM Sample1
UNION
SELECT NAME FROM Sample2;
EX: Table Sample1
ID NAME
-------
1 A
-------
2 B
-------
Table Sample 2
ID NAME
--------
1 C
--------
2 B
------
Output
NAME
----
A
---
B
---
C
---

Related

Get the list of name column values which are not common in both the tables?

recently i gave an interview where the question was
suppose there are two tables in database.
Table T1 has a column named "name" in it and few other columns
Table T2 also has a column name "name" and few other columns
suppose table T1 has values in name column as
[n1,n2,n3,n4,n5]
and values in the "name" column of table T2 are
[n2,n4]
then output should be
[n1,n3,n5] as n2 and n4 are common in both tables
we needs to find the list of names which are not common in both the tables.
The solution that i provided him was using join in the below form
select name from table1 where name not in (select t1.name from table1 t1 join table2 t2 on t1.name=t2.name)
UNION
select name from table2 where name not in (select t1.name from table1 t1 join table2 t2 on t1.name=t2.name)
But he said there is still a better solution. I was not able to come up with any different and more efficient solution. What is the other efficient way to get the list of names if there is any?
If the NAME column does not have NULL values, there is also
select distinct(coalesce(a.name, b.name)) name
from table1 a
full join table1 b on a.name = b.name
where a.name is null or b.name is null
(Corrected WHERE condition, sorry...)
Use FULL OUTER JOIN:
SELECT DISTINCT(COALESCE(t1.NAME, t2.NAME)) AS NAME
FROM TABLE1 t1
FULL OUTER JOIN TABLE2 t2
ON t2.NAME = t1.NAME
WHERE t1.NAME IS NULL OR
t2.NAME IS NULL
A FULL OUTER JOIN is similar to a LEFT OUTER JOIN unioned with a RIGHT OUTER JOIN - it returns rows where data exists in the first table but not the second, or where it data exists in the second table but not the first. You could get the same effect by using
SELECT t1.NAME
FROM TABLE1 t1
LEFT OUTER JOIN TABLE2 t2
ON t2.NAME = t1.NAME
WHERE t2.NAME IS NULL
UNION
SELECT t2.NAME
FROM TABLE1 t1
RIGHT OUTER JOIN TABLE2 t2
ON t2.NAME = t1.NAME
WHERE t1.NAME IS NULL
and in fact the above is what you'd need to do if you were using a database which doesn't support the FULL OUTER JOIN syntax (e.g. MySQL, the last time I looked).
See this dbfiddle
Union the tables and return the values that don't have a count of 2:
create table t1 (
c1 int
);
create table t2 (
c1 int
);
insert into t1 values ( 1 );
insert into t1 values ( 3 );
insert into t2 values ( 2 );
insert into t2 values ( 3 );
commit;
select c1 only_in_one_table
from (
select 'T1' t, c1 from t1
union
select 'T2' t, c1 from t2
)
group by c1
having count(*) <> 2;
ONLY_IN_ONE_TABLE
1
2
I'm not a fan of not in with subqueries, because it behaves unexpectedly with null values. And the person asking would have to explain what "better" means. Your version is actually reasonable.
I might be inclined to approach this using aggregation:
select name
from ((select distinct name, 1 as in_table1, 0 as in_table2
from table1
) union all
(select distinct name, 0 as in_table1, 0\1 as in_table2
from table2
)
) t
group by name
having max(in_table1) <> max(in_table2);
In a real world case, you would probably have a separate table with all names. If so:
select n.*
from names n
where (not exists (select 1 from table1 t1 where t1.name = n.name) and
exists (select 1 from table2 t2 where t2.name = n.name
) or
(exists (select 1 from table1 t1 where t1.name = n.name) and
not exists (select 1 from table2 t2 where t2.name = n.name
);
This is usually the fastest approach because it does not involve any aggregation or duplicate removal.
If you want to use SET operator then find the solution as below:
CREATE TABLE TABLE1(NAME VARCHAR2(100));
CREATE TABLE TABLE2(NAME VARCHAR2(100));
INSERT INTO TABLE1 VALUES('A');
INSERT INTO TABLE1 VALUES('B');
INSERT INTO TABLE1 VALUES('C');
INSERT INTO TABLE2 VALUES('A');
INSERT INTO TABLE2 VALUES('B');
INSERT INTO TABLE2 VALUES('D');
SELECT
NAME
FROM
(
SELECT
NAME
FROM
TABLE1
UNION
SELECT
NAME
FROM
TABLE2
)
WHERE
NAME NOT IN (
SELECT
NAME
FROM
TABLE1
JOIN TABLE2 USING ( NAME )
);
Cheers!!
Yet another possible solution:
Find those that are in the first table but not in the second table using the MINUS operator (which is Oracle's implementation of the standard EXCEPT). Then UNION that with those that are in the second but not in the first.
(
select name
from t1
minus
select name
from t2
)
union all
(
select name
from t2
minus
select name
from t1
);
Given this setup:
create table t1
(
name varchar(10)
);
insert into t1 values ('Arthur');
insert into t1 values ('Zaphod');
create table t2
(
name varchar(10)
);
insert into t2 values ('Tricia');
insert into t2 values ('Zaphod');
This returns:
NAME
------
Arthur
Tricia
select id from((select id from table1)
union all
(select id from table2)) as t1
group by id having count(id)=1
Using the basic set operations the following query should work.
(
select name from table1
union all
select name from table2
)
minus
(
select name from table1
intersect
select name from table2
)
;
Regards
Akash

Compare a two column with the same table to remove duplicate

A sample table with two column and I need to compare the column 1 and column 2 to the same table records and need to remove the column 1 + column 2 = column 2+column 1.
I tried to do self join and case condition. But its not working
If I understand correctly, you can run a simple select like this if you have all reversed pairs in the table:
select col1, col2
from t
where col1 < col2;
If you have some singletons, then:
select col1, col2
from t
where col1 < col2 or
(col1 > col2 and
not exists (select 1
from t t2
where t2.col1 = t.col2 and
t2.col2 = t.col1
)
);
You can use the except operator.
"EXCEPT returns distinct rows from the left input query that aren't output by the right input query."
SELECT C1, C2 FROM table
Except
SELECT C2, C1 FROM table
Example with your given data set : dbfiddle
I am posting the answer based on oracle database and also the columns are string/varchar:
delete from table where rowid in (
select rowid from table
where column1 || column2 =column2 || column1 )
Feel free to provide more input and we can tweak the answer.
Okay. There might be a simpler way of doing this but this might work as well. {table} is to be replaced with your table name.
;with orderedtable as (select t1.col1, t1.col2, ROW_NUMBER() OVER(ORDER BY t1.col1, t1.col2 ASC) AS rownum
from (select distinct t2.col1, t2.col2 from {table} t2) as t1)
select f1.col1, f1.col2
from orderedtable f1
left join orderedtable f2 on f1.col1 = f2.col2 and f1.col2 = f2.col1 and f1.rownum < f2.rownum
where f2.rownum is null
The SQL below will get the reversed col1 and col2 rows:
select
distinct t2.col1,t1.col2
from
table t1
join
table t2 on t1.col1 = t2.col2 and t1.col2 = t2.col1
And when we get these reversed rows, we can except them with the left join clause, the complete SQL is:
select
t.col1,t.col2
from
table t
left join
(
select
distinct t2.col1,t1.col2
from
table t1
join
table t2 on t1.col1 = t2.col2 and t1.col2 = t2.col1
) tmp on t.col1 = tmp.col1 and t.col2 = tmp.col2
where
tmp.col1 is null
Is it clear?

Find unmatched rows between two tables

Given this setup:
CREATE TABLE table1 (column1 text, column2 text);
CREATE TABLE table2 (column1 text, column2 text);
INSERT INTO table1 VALUES
('A', 'A')
, ('B', 'N')
, ('C', 'C')
, ('B', 'A');
INSERT INTO table2 VALUES
('A', 'A')
, ('B', 'N')
, ('C', 'X')
, ('B', 'Y');
How can I find missing combinations of (column1, column2) between these two tables? Rows not matched in the other table.
The desired result for the given example would be:
C | C
B | A
C | X
B | Y
There can be duplicate entries so we'd want to omit those.
One method is union all:
select t1.col1, t1.col2
from t1
where (t1.col1, t1.col2) not in (select t2.col1, t2.col2 from t2)
union all
select t2.col1, t2.col2
from t2
where (t2.col1, t2.col2) not in (select t1.col1, t1.col2 from t1);
If there are duplicates within a table, you can remove them by using select distinct. There is no danger of duplicates between the tables.
Seems to be a perfect task for set operations:
( --all rows from table 1 missing in table 2
select *
from table1
except
select *
from table2
)
union all -- both select return distinct rows
( -- all rows in table 2 missing in table 1
select *
from table2
except
select *
from table1
)
You can try to use not exists with a subquery, then use UNION ALL
select Column1,Column2 from table1 t1
where NOT exists
(
select 1
FROM table2 t2
where t1.Column1 = t2.Column1 or t1.Column2 = t2.Column2
)
UNION ALL
select Column1,Column2 from table2 t1
where NOT exists
(
select 1
FROM table1 t2
where t1.Column1 = t2.Column1 or t1.Column2 = t2.Column2
)
You can try set operations. EXCEPT to find the rows in table but not in the other and UNION to put the partial results into one.
(SELECT column1,
column2
FROM table1
EXCEPT
SELECT column1,
column2
FROM table2)
UNION
(SELECT column1,
column2
FROM table2
EXCEPT
SELECT column1,
column2
FROM table1);
If you don't need duplicate elimination you can try to use the ALL variants (EXCEPT ALL and UNION ALL). They are generally faster, as the DBMS doesn't have to look for and eliminate duplicates.
The devil is in the details with this seemingly simple task.
Short and among the fastest:
SELECT col1, col2
FROM (SELECT col1, col2, TRUE AS x1 FROM t1) t1
FULL JOIN (SELECT col1, col2, TRUE AS x2 FROM t2) t2 USING (col1, col2)
WHERE (x1 AND x2) IS NULL;
The FULL [OUTER] JOIN includes all rows from both sides, but fills in NULL values for columns of missing rows. The WHERE conditions (x1 AND x2) IS NULL identifies these unmatched rows. Equivalent: WHERE x1 IS NULL OR x2 IS NULL.
To eliminate duplicate pairs, add DISTINCT (or GROUP BY) at the end - cheaper for few dupes:
SELECT DISTINCT col1, col2
FROM ...
If you have many dupes on either side, it's cheaper to fold before the join:
SELECT col1, col2
FROM (SELECT DISTINCT col1, col2, TRUE AS x1 FROM t1) t1
FULL JOIN (SELECT DISTINCT col1, col2, TRUE AS x2 FROM t2) t2 USING (col1, col2)
WHERE (x1 AND x2) IS NULL;
It's more complicated if there can be NULL values. DISTINCT / DISTINCT ON or GROUP BY treat them as equal (so dupes with NULL values are folded in the subqueries above). But JOIN or WHERE conditions must evaluate to TRUE for rows to pass. NULL values are not considered equal in this, the FULL [OUTER] JOIN never finds a match for pairs containing NULL. This may or may not be desirable. You just have to be aware of the difference and define your requirements.
Consider the added demo in the SQL Fiddle
If there are no NULL values, no duplicates, but an additional column defined NOT NULL in each table, like the primary key, let's name each id, then it can be as simple as:
SELECT col1, col2
FROM t1
FULL JOIN t2 USING (col1, col2)
WHERE t1.id IS NULL OR t2.id IS NULL;
Related:
Select rows which are not present in other table
PostgreSQL - Create table as select with distinct on specific columns

SQL - Null value should match with not null value with another table

Table 1
Column1 Column2 Column 3
A Null 12
B Null 15
C 0 15
Table 2
Column2 Column3
0 15
0 12
I have table 1 and Table 2 , Here I'm passing table 2 parameters to table 1 which should return the column1 but it should match with Null values like the below scenario
If I pass (0, 15) to table 1 then it should return 'C' not 'B'.
If I Pass (0,12) to table 1 then it should return 'A'
Anytime it should return one value not multiple vales.
Could you please help me with this logic ?
You could do this as a union:
select Column1 from
(
select Table1.Column1 as Column1,Table1.Column2 as Column2
from Table1
join Table2 on
Table1.Column2=Table2.Column2 and Table1.Column3=Table2.Column3
UNION
select Table1.Column1 as Column1,Table1.Column2 as Column2
from Table1
join Table2 on
Table1.Column2 is NULL and Table1.Column3=Table2.Column3
) as Unioned
ORDER BY Column2 NULLS LAST
LIMIT 1;
The UNION discards duplicates, but you could always wrap the entire statement in another SELECT if you explicitly need to tell it to return at most one value.
select *
from table2 t
left outer join table1 t1 on t.column2=t1.column2 and t.column3=t1.column3
left outer join table1 t2 on t2.column2 is null and t.column3=t2.column3
where t1.column2 is not null or t2.column3 is not null
SQL Server
WITH T1
as
(SELECT COLUMN1,COLUMN2,
case when COLUMN2 is null then 0 else COLUMN2 end AS TRANSFORMED_COLUMN2,
row_number() OVER (partition by isnull(column3,2) ORDER BY isnull(COLUMN2,2) asc) AS rnk,
COLUMN3
FROM TABLE1)
SELECT
T1.COLUMN1,
T2.COLUMN2,
T2.COLUMN3
FROM
T1
INNER JOIN
(SELECT COLUMN2,COLUMN3 FROM TABLE2) T2
ON T1.TRANSFORMED_COLUMN2 = T2.COLUMN2
AND T1.COLUMN3=T2.COLUMN3
where T1.rnk=1
By using CTE, you will running through the tables just once.
SELECT t1.* FROM table1 t1
INNER JOIN table2 t2
ON NVL(t1.column2,0) = t2.column2 and t1.column3 = t2.column3

Using the names of columns stored within fields to retrieve data from a different table

I was wondering if there exists code to accomplish the following in SQL-Server 2008?
Table 1:
id column name
-------------------
1 col1
2 col2
3 col3
4 col2
Table 2:
col1 col2 col3
--------------------
a b c
Result Table:
id data
--------------------
1 a
2 b
3 c
4 b
Thanks in advance, I really have no idea how to do this.
You can use UNPIVOT table2 to access the data from the columns:
select t1.id, t2.value
from table1 t1
left join
(
select value, col
from table2
unpivot
(
value
for col in (col1, col2, col3)
) u
) t2
on t1.name = t2.col
see SQL Fiddle with Demo
Or you can use a UNION ALL to access the data in table2:
select t1.id, t2.value
from table1 t1
left join
(
select col1 value, 'col1' col
from table2
union all
select col2 value, 'col2' col
from table2
union all
select col3 value, 'col3' col
from table2
) t2
on t1.name = t2.col
see SQL Fiddle with Demo
I dont see how you do it withou a column connection them:
Table1:
ID
ColumnName
Table2:
Table1ID
Letter
Select table1.id, table2.Letter
from table1
inner join table2 on table1.ID = table2.Table1ID
You can do this with a case statement and cross join:
select t1.id,
(case when t1.columnname = 'col1' then t2.col1
when t1.columnname = 'col2' then t2.col2
when t1.columnname = 'col3' then t2.col3
end) as data
from table1 t1 cross join
table2 t2