Find columns whose values are distinct in two tables - sql

I have two tables having same columns.I want to get those columns whose values are distinct in both tables.How Can I achieve this?please help.Iam stuck.
imageid is primary key in both tables.Its not necessary that imageids present in first table should be present
on second table.
First table:
imageid name id
1 priya 001
2 neha 002
3 divya 003
4 santo 004
Second table:
imageid name id
1 priy 001
2 neha 003
4 santo 004
Result
imageid firstdata seconddata columnname
1 priy priya name
2 002 003 id

Assuming you have no duplicates, then you can do this with a basic inner join with union all:
select t1.imageid, t1.name as firstdata, t2.name as seconddata, 'name' as colname
from t1 join
t2
on t1.imageid = t2.imageid
where t1.name <> t2.name
union all
select t1.imageid, t1.id as firstdata, t2.id as seconddata, 'id'
from t1 join
t2
on t1.imageid = t2.imageid
where t1.id <> t2.id;
Depending on types and on the database, you might need to cast the ids to a string.

I found the following method on AskTom.com years ago and have kept it as a code template ever since. I find it's reasonably fast and I use it frequently.
SELECT COUNT(src1) AS in_first_table, COUNT(src2) AS in_second_table, imageid, name, id
FROM (SELECT imageid, name, id,
1 AS src1,
to_number(NULL) AS src2
FROM first_table
UNION ALL
SELECT imageid, name, id,
to_number(NULL) AS src1,
2 AS src2
FROM second_table
)
GROUP BY imageid, name, id
HAVING COUNT(src1) <> COUNT(src2)
ORDER BY 3, 1 DESC;
The first two columns (counts) indicate how many records found in that table, which can identify rows where the tables have multiple matching records.
I've also used this to compare very complex queries by putting them in a WITH clause, so the main query is easier to read.
For example:
WITH first_t AS
(SELECT imageid, NAME, id
FROM first_table),
second_t AS
(SELECT imageid, NAME, id
FROM second_table)
SELECT COUNT(src1) AS in_first_table,
COUNT(src2) AS in_second_table,
imageid, NAME, id
FROM (SELECT first_t.*,
1 AS src1,
to_number(NULL) AS src2
FROM first_t
UNION ALL
SELECT second_t.*,
to_number(NULL) AS src1,
2 AS src2
FROM second_t)
GROUP BY imageid,
NAME,
id
HAVING COUNT (src1) <> COUNT (src2)

UNION will return unique records on the result. If you specify ALL (UNION ALL) will keep duplicates on the result set.
SELECT column1 column2 FROM first_table
UNION
SELECT column1 column2 FROM second_table

Related

Combining access sql tables in a query side by side

I have 2 tables containing different data, linked by a column "id", except the id is repeated multiple times
For example,
Table 1:
id grade
1 A
1 C
Table 2:
Id company
1 Alpha
1 Beta
1 Charlie
The number of rows would be inconsistent, table 1 may sometimes have more/less/equal rows compared to table 2. How am I able to combine/merge them into this outcome:
id grade company
1 A Alpha
1 C Beta
1 Charlie
I am using Microsoft access' query.
This is a real pain in MS Access. But you can do it by using a subquery to generate sequence numbers. Here is one method assuming that the rows are unique:
select id, max(grade) as grade, max(company) as company
from ((select id, grade, null as company,
(select count(*)
from table1 as tt1
where tt1.id = t1.id and tt1.grade <= t1.grade
) as seqnum
from table1 as tt1
) union all
(select id, null as grade, company,
(select count(*)
from table2 as tt2
where tt2.id = t2.id and tt2.company <= t1.company
) as seqnum
from table2 as tt2
)
) t12
group by id, seqnum;
This would be much simpler in almost any other database.

SQL - How to Order By in UNION query

Is there a way to union two tables, but keep the rows from the first table appearing first in the result set? However orderby column is not in select query
For example:
Table 1
name surname
-------------------
John Doe
Bob Marley
Ras Tafari
Table 2
name surname
------------------
Lucky Dube
Abby Arnold
Result
Expected Result:
name surname
-------------------
John Doe
Bob Marley
Ras Tafari
Lucky Dube
Abby Arnold
I am bringing Data by following query
SELECT name,surname FROM TABLE 1 ORDER BY ID
UNION
SELECT name,surname FROM TABLE 2
The above query is not keeping track of order by after union.
P.S - I dont want to show ID in my select query
I am getting ORDER BY Column by joining tables. Following is my real query
SELECT tbl_Event_Type_Sort_Orders.Appraisal_Event_Type_ID AS Appraisal_Event_Type_ID , ISNULL(tbl_Appraisal_Event_Types.Appraisal_Event_Type_Display_Name, 'UnCategorized') AS Appraisal_Event_Type_Display_Name
INTO #temptbl
FROM tbl_Event_Type_Sort_Orders
INNER JOIN tbl_Appraisal_Event_Types
ON tbl_Event_Type_Sort_Orders.Appraisal_Event_Type_ID = tbl_Appraisal_Event_Types.Appraisal_Event_Type_ID
WHERE 1=1
AND User_Name='abc'
ORDER BY tbl_Event_Type_Sort_Orders.Sort_Order
SELECT * FROM #temptbl
UNION
SELECT DISTINCT (tbl_Appraisal_Event_Types.Appraisal_Event_Type_ID) AS Appraisal_Event_Type_ID , ISNULL(tbl_Appraisal_Event_Types.Appraisal_Event_Type_Display_Name, 'UnCategorized') AS Appraisal_Event_Type_Display_Name
FROM tbl_Appraisal_Event_Types
INNER JOIN tbl_Appraisal_Events
ON tbl_Appraisal_Event_Types.Appraisal_Event_Type_ID = tbl_Appraisal_Events.Event_Type_ID
INNER JOIN tbl_Appraisals
ON tbl_Appraisal_Events.Appraisal_ID = tbl_Appraisal_Events.Appraisal_ID
WHERE 1=1
AND ((tbl_Appraisals.Assigned_To_Staff_User) = 'abc' OR (tbl_Appraisals.Assigned_To_Staff_User2) = 'abc' OR (tbl_Appraisals.Assigned_To_Staff_User3) = 'abc')
Put a UNION ALL in a derived table. To keep duplicate elimination, do select distinct and also add a NOT EXISTS to second select to avoid returning same person twice if found in both tables:
select name, surname
from
(
select distinct name, surname, 1 as tno
from table1
union all
select distinct name, surname, 2 as tno
from table2 t2
where not exists (select * from table1 t1
where t2.name = t1.name
and t2.surname = t1.surname)
) dt
order by tno, surname, name
You can use a column for the table and one for the ID to order by:
SELECT x.name, x.surname FROM (
SELECT ID, TableID = 1, name, surname
FROM table1
UNION ALL
SELECT ID = -1, TableID = 2, name, surname
FROM table2
) x
ORDER BY x.TableID, x.ID
You can write as below, if you are ok with duplicate data then please use UNION ALL it will be faster:
SELECT NAME, surname FROM (
SELECT ID,name,surname FROM TABLE 1
UNION
SELECT ID,name,surname FROM TABLE 2 ) t ORDER BY ID
this will order the first row sets first then by anything you need
(haven't tested the code)
;with cte_1
as
(SELECT ID,name,surname,1 as table_id FROM TABLE 1
UNION
SELECT ID,name,surname,2 as table_id FROM TABLE 2 )
SELECT name, surname
FROM cte_1
ORDER BY table_id,ID
simply use a UNION clause with out order by.
SELECT name,surname FROM TABLE 1
UNION
SELECT name,surname FROM TABLE 2
if you wanted to order first table use the below query.
;WITH cte_1
AS
(SELECT name,surname,ROW_NUMBER()OVER(ORDER BY Id)b FROM TABLE 1 )
SELECT name,surname
FROM cte_1
UNION
SELECT name,surname
FROM TABLE 2

Update using minis

Hello I want to update table2 if the data does not match table 1. If there are results in the below query I would like table2 to be updated
Select id, name, desc
From table1
Minus
Select id, name, desc
From table2
Table1
Id, name, desc
1 bob green
2 Sam Blue
Table2
Id, name, desc
1 bob yellow
2 sam b Red
I want table2 to have the same data as table1
Table2
Id, name, desc
1 bob Green
2 Sam Blue
If you want Table2 to have the same data as Table1 then I would recommend truncating it and re-inserting the data:
truncate table table2;
insert into table2(id, name, desc)
select id, name, desc
from table1;
This operation is usually going to be faster than a bunch of updates.
EDIT:
In Oracle, you can use merge or set the fields as:
update table2
set (name, desc) = (select name, desc from table1 where table1.id = table2.id);
If you like, you can add:
where (name, desc) <> (select name, desc from table1 where table1.id = table2.id)

How do you make a column value slide to the right or the left using SQL?

This was an interview question.
If I have a table like this:
ID FirstName LastName
-- --------- --------
1 Aaron Aames
2 Malcolm Middle
3 Zamon Zorr
How can I get output that looks like this?
Aaron Aames
Aames Malcolm
Malcolm Middle
Middle Zamon
Zamon Zorr
Note: If you need a specific dialect to do it, use T-SQL.
Here is another way using a self-join.
CREATE TABLE temp (ID INT IDENTITY, FirstName VARCHAR(25), LastName VARCHAR(25));
INSERT INTO temp VALUES
(N'Aaron', N'Aames'),
(N'Malcolm', N'Middle'),
(N'Zamon', N'Zorr');
WITH names(ID, Name, ColNum) AS(
SELECT
ID, FirstName, 1
FROM temp
UNION ALL
SELECT
ID, LastName, 2
FROM temp
),
numbered AS(
SELECT
rn = ROW_NUMBER() OVER(ORDER BY ID, ColNum),
Name
FROM names
)
SELECT
n.Name AS Name1, n2.Name AS Name2
FROM numbered n
INNER JOIN numbered n2
ON n.rn = n2.rn - 1
DROP TABLE temp
http://sqlfiddle.com/#!3/d91c4/2
You have really high reputation, so this isn't just a "they asked me at an interview" kind of question.
There are several approaches. I think the one that I would take is a union all. Recognize that every other row is from the table. The rest are from joining one row to the next. So, that suggests:
select firstname, lastname
from likethis t
union all
select t.lastname, lead(t.firstname) over (order by id)
from likethis t
Alas, this gives you six rows instead of five, so that last one needs to be filtered out:
select firstname, lastname
from (select firstname, lastname
from likethis t
union all
select t.lastname, lead(t.firstname) over (order by id)
from likethis t
) t
where lastname is not null
order by firstname;
Note: I cannot determine if the sort criteria is alphabetical or by id; these solutions assume it is alphabetical.
Second note: I'm guessing this is not the solution they have in mind. They probably are looking for a self-join. But why bother when lead() does the work for you.
I think it could be solved this way:
SELECT
t.LastName AS FirstName, t2.FirstName AS LastName
FROM
t
INNER JOIN t as t2 ON t2.ID - 1 = t.ID
UNION
SELECT
t3.FirstName, t3.LastName
FROM t AS t3
As far as I've checked correctly it should give the final result set the following way:
Aaron Aames <= originates from t3: where t3.ID = 1
Aames Malcolm <= originates from (t1, t2) Join: where t2.ID = 2 and t.ID = 1
Malcolm Middle <= originates from t3: where t3.ID = 2
Middle Zamon <= originates from (t1, t2) Join: where t2.ID = 3 and t.ID = 2
Zamon Zorr <= originates from t3: where t3.ID = 3

ORDER BY with a UNION of disparate datasets (T-SQL)

I have a query that UNION's two somewhat similar datasets, but they both have some columns that are not present in the other (i.e., the columns have NULL values in the resulting UNION.)
The problem is, I need to ORDER the resulting data using those columns that only exist in one or the other set, to get the data in a friendly format for the software-side.
For example: Table1 has fields ID, Cat, Price. Table2 has fields ID, Name, Abbrv. The ID field is common between the two tables.
My query looks like something like this:
SELECT t1.ID, t1.Cat, t1.Price, NULL as Name, NULL as Abbrv FROM t1
UNION
SELECT t2.ID, NULL as Cat, NULL as Price, t2.Name, t2.Abbrv FROM t2
ORDER BY Price DESC, Abbrv ASC
The ORDER BY is where I'm stuck. The data looks like this:
100 Balls 1.53
200 Bubbles 1.24
100 RedBall 101RB
100 BlueBall 102BB
200 RedWand 201RW
200 BlueWand 202BW
...but I want it to look like this:
100 Balls 1.53
100 RedBall 101RB
100 BlueBall 102BB
200 Bubbles 1.24
200 RedWand 201RW
200 BlueWand 202BW
I'm hoping this can be done in T-SQL.
Select ID, Cat, Price, Name, Abbrv
From
(SELECT t1.ID, t1.Cat, t1.Price, t1.Price AS SortPrice, NULL as Name, NULL as Abbrv
FROM t1
UNION
SELECT t2.ID, NULL as Cat, NULL as Price, t1.Price as SortPrice, t2.Name, t2.Abbrv
FROM t2
inner join t1 on t2.id = t1.id
) t3
ORDER BY SortPrice DESC, Abbrv ASC
Somehow you have to know the data in table 2 are linked to table 1 and share the price. Since the Null in abbrv will come first, there is no need to create a SortAbbrv column.
You should use UNION ALL instead of UNION to save the cost of duplicate checking.
SELECT *
FROM
(
SELECT t1.ID, t1.Cat, t1.Price, NULL as Name, NULL as Abbrv FROM t1
UNION ALL
SELECT t2.ID, NULL as Cat, NULL as Price, t2.Name, t2.Abbrv FROM t2
) as sub
ORDER BY
ID,
CASE WHEN Price is not null THEN 1 ELSE 2 END,
Price DESC,
CASE WHEN Abbrv is not null THEN 1 ELSE 2 END,
Abbrv ASC
A quick solution would be to do 2 inserts into a temp table or a table variable and as part of insert into the temp table you can set a flag column to help with sorting and then order by that flag column.
Off the top of my head i would say the worst case scenario is you create a temporary table with all the fields do an INSERT INTO the temp table from both T1 & T2 then SELECT from the temp table with an order by.
ie. Create a temp table (eg. #temp) with fields Id, Cat, Price, Name, Abbrv, and then:
SELECT Id, Cat, Price, null, null INTO #temp FROM T1
SELECT Id, null, null, Name, Abbrv INTO #temp FROM T2
SELECT * FROM #temp ORDER BY Id, Price DESC, Abbrv ASC
NB: I'm not 100% sure on the null syntax from the inserts but i think it will work.
EDIT: Added ordering by Price & Abbrv after id... if Id doesn't link T1 & T2 then what does?