Differences between two tables - sql

Data is like so, (table1 links up to table2) on table1.col2 = table2.col2
Based on that criteria,
Employee 5 below assigned to Area 1 in first table, however in second table that employee is not assigned to Area 1, so the result that would return would only be the first record of the first table (emp5, a1)
Example below
Table1
Col1 Col2
-------------
emp5 A1
emp6 A1
emp5 A2
Table2
Col1 Col2
--------------
emp7 A1
emp6 A1
emp5 A2

You can use MINUS, it is more intuitive. The syntax can be different in SQL Server, MySQL or Oracle, like you can see http://blog.sqlauthority.com/2008/08/07/sql-server-except-clause-in-sql-server-is-similar-to-minus-clause-in-oracle/
But I like MINUS, for instance
select
t1.Col1,
t1.Col2
from table1 t1
MINUS
select
t2.Col1,
t2.Col2
from table2 t2
This way, you can think like sets (math)!

This is tricky. You need employees who are in both tables. Then you need to check that col2 is different on one of the rows.
The following does this comparison using union all:
select col1, col2, max(which)
from ((select col1, col2, 1 as which
from table1 t1
where exists (select 1 from table2 t2 where t2.col1 = t1.col1)
) union all
(select col1, col2, 2 as which
from table2 t2
where exists (select 1 from table1 t1 where t2.col1 = t1.col1)
)
) tt
group by col1, col2
having count(*) = 1
This will also tell you which table has the extra row.

select table1.*
from table1
left join table2
on table1.col1 = table2.col1
and table1.col2 = table2.col2
where table2.col1 is null
if you only want those from table 1 that are also assigned to another project then
select distinct table1.*
from table1
join table2 as t2not
on t2not.col1 = table1.col1
and t2not.col2 <> table1.col2
left join table2
on table1.col1 = table2.col1
and table1.col2 = table2.col2
where table2.col1 is null

Related

Join or Union table with same Characteristics and different Measures

I would like to understand the easy/better way to join 2 tables with same characteristics and different measures as an example described below:
tab1
Col1
Col2
Measure1
1
1
10
1
2
5
tab2
Col1
Col2
Measure2
1
1
20
2
1
25
Expected Result
Col1
Col2
Measure1
Measure2
1
1
10
20
1
2
5
0
2
1
0
25
Questions:
How to avoid message: Ambiguous column name col1?
How to create a correct Join?
I have tried:
select col1, col2, t1.Measure1, t2.Measure2
from tab1 t1
full outer jon tab2 t2
on t1.col1 = t2.col1
and t1.col2 = t2.col2
I have tried a Union and it works, but i am looking a easy way using joins:
Select col1, col2, Measure1, 0 as Measure2 From tab1
Union
Select col1, col2, 0 as Measure1, Measure2 From tab2
The full join is the correct approach. But you need to disambiguate col1 and col2 in the select clause: both tables have both columns, so it is unclear to which column an unprefixed col1 refers.
A typical approach uses coalesce():
select
coalesce(t1.col1, t2.col1) col1,
coalesce(t1.col2, t2.col2) col2,
coalesce(t1.measure1, 0) measure1,
coalesce(t2.measure2, 0) measure2
from tab1 t1
full outer jon tab2 t2
on t1.col1 = t2.col1 and t1.col2 = t2.col2
Note that you also need coalesce() around the measures to return 0 instead of null on "missing" values.
In some databases (eg Postgres), you can use the using syntax to declare the join conditions for columns that have the same name across the tables ; this syntax automagically disambiguates the unprefixed column names, so:
select
col1,
col2,
coalesce(t1.measure1, 0) measure1,
coalesce(t2.measure2, 0) measure2
from tab1 t1
full join tab2 t2 using (col1, col2)
You should reference source tables for col1 and col2 as well.
As you're using FULL OUTER JOIN I'd recommend using COALESCE statement.
SELECT COALESCE(t1.col1, t2.col1) as col1,
COALESCE(t1.col2, t2.col2) as col2,
t1.Measure1,
t2.Measure2
FROM tab1 t1
FULL OUTER JOIN tab2 t2
on t1.col1 = t2.col1
and t1.col2 = t2.col2

Find unmatched records using inner join without using WHERE clause

I have a tables Table1 and Table2 like this:
Table1
Col1
====
A
B
Table2
Col1
====
A
B
C
D
Now using an INNER JOIN I need to find unmatched records from Table2
(Note: WHERE clause is NOT ALLOWED)
Expected output:
Col1
====
C
D
What can be the SQL Query for this?
I have already tried following its not working.
Select Distinct
Table2.col1
from
Table1
Inner Join
Table2 On Table1.col1 <> Table2.col1
Jumped the gun the first time - should have read properly, sorry. Had to think about this one:
SELECT Table2.col1
FROM Table1 RIGHT JOIN Table2
ON Table1.col1 = Table2.col1
GROUP BY Table1.col1, Table2.col1
HAVING Table1.col1 IS NULL;
You can use the following query
SELECT * FROM Table2
WHERE Col1 NOT IN
(SELECT Col1 FROM Table1)
The following query also works
SELECT Col1 FROM Table2
EXCEPT
SELECT Col1 FROM Table1
nobody said it had to be sensible did they?
with
t1 as (
select col1 as c1
, row_number() over (order by col1 ASC) as rn1
from table1
),
t2 as (
select col1 as c2
, row_number() over (order by col1 DESC) as rn2
from table2
)
select
c2 as Col1
from t2
inner join t1 on t2.rn2 = t1.rn1 and t2.c2 <> t1.c1
order by c2 ASC
;
http://sqlfiddle.com/#!15/4747e/1 (postgres 9.3.1)

copy a table into a new table and add a new column on SQL server 2008

I need to copy a table into a new table on SQL server 2008.
Also, add a new column into the new table.
The values of the new column depends on the compare result between the new table and another table.
Example,
Table1:
col1 col2 col3
abc 346 6546
hth 549 974
Expected Table1_new:
col1 col2 col3 col4
abc 346 6546 1
hth 549 974 0
Table2:
col1
abc
sfsdf
If Table2's col1 appear in Table1 col1, mark col4 as 1 in Table1_new, else mark as 0.
The code does not work
SELECT *,
(
SELECT 1 as col4
FROM Table2 as a
INNER JOIN Table1 as b
on b.col1 = a.col1
SELECT 0 as col4
FROM Table2 as a
INNER JOIN Table1 as b
on b.col1 <> a.col1 # I do not know how to do this !!!
)
INTO table1_new
FROM table1
Any help would be appreciated.
You could use an outer join:
SELECT table1.col1, col2, col3,
CASE WHEN table2.col1 IS NULL THEN 0 ELSE 1 END AS col4
INTO table1_new
FROM table1
LEFT OUTER JOIN table2 ON table1.col1 = table2.col1
You can do this in several ways. The following uses an exists clause in a case statement:
insert into table1_new(col1, col2, col3, col4)
select col1, col2, col3,
(case when exists (select 1 from table2 t2 where t2.col1 = t1.col1)
then 1 else 0
end)
from table1 t1;
You can also do this with a left outer join, but you run the risk of duplicates if t2 has duplicates.
INSERT INTO T2
SELECT COL1,COL2,COL3, (COL1+COL2) FROM T1
Note that instead of the (COL1+COL2) section you could run other expressions or possibly even a function.
Try something like this using CASE
SELECT
CASE
WHEN b.col1 = a.col1 THEN 1
ELSE 0
END as col4
FROM Table1 as a
LEFT JOIN Table2 as b
on b.col1 = a.col1
EDIT: Table1 should be the left table as mentioned in #Muerniks answer.
In addition to what the others already suggested: If you can't solve the problem in one step, try to make smaller steps. E.g. first initialize Table1.col4 with zero:
INSERT INTO Table1_new (col1,col2,col3,col4)
SELECT col1,col2,col3,0
FROM Table1
After that you will only need to identify the records which have matching partners in Table2 which is a classical inner join:
UPDATE t1 SET col4=1
FROM Table1_new t1
JOIN Table2 t2 ON t2.col1=t1.col1

Cleaning up and simplifying a nested SQL statement

I'm trying to determine if there is a better way to do this in SQL. My goal is to run one query which returns two values that are to be used for another query. See below
select *
from table2
where col1 =
( select col1
from table1
where id = 123 )
and col2 =
( select col2
from table1
where id = 123 );
Is there a way to simplify this code by either doing a where clause that checks both values against one nested query, or by running the first querying and somehow setting the values of col1 and col2 to variables that I can use in the second query?
You can do
select *
from table2
where (col1, col2) = (select col1, col2
from table1
where id = 123)
SELECT DISTINCT a.*
FROM table2 a
INNER JOIN table1 b
ON a.col1 = b.col1
AND a.col2 = b.col2
WHERE b.id = 123
you can simply use query as below
select t2.* from table2 t2,table1 t1 where t1.col1=t2.col1 and
t1.col2=t2.col2 and t1.id=123
Seems like you've got it backwards. Since you know exactly what you want from table1 (so, presumably, the query is smaller), you should start by getting the data from table1, then join the releveant rows from table2:
select table2.*
from table1
inner join table2
on table2.col1 = table1.col1
and table2.col2 = table1.col2
where table1.id = 123

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