Finding unmatched rows of 2 tables in SQL - sql

I have 2 tables with 3 columns that are suppose to have the same information.
I would like have a query that selects only the rows that don't have a complete row match. Below is an example of the 2 tables I would like to match:
Table 1
ID FPRICE FPRODUCT
1 1 A
2 2 B
3 3 C
4 4 D
5 5 F
Table 2
ID TPRICE TPRODUCT
1 1 A
2 2 B
3 3 C
4 5 D
6 6 E
Desired Output:
ID FPRICE FPRODUCT TPRICE TPRODUCT
4 4 D 5 D
5 5 F NULL NULL
6 NULL NULL 6 E

Easier to verify if we build some DDL and fillwith sample data, but I think this would do it. It takes a full join to find records with a partial match and then filters out records with a full match.
sqlfiddle.com
CREATE TABLE Table1 (ID INT, FPRICE INT, FPRODUCT CHAR(1))
INSERT INTO Table1 (ID,FPRICE,FPRODUCT) VALUES
(1, 1, 'A')
,(2, 2, 'B')
,(3, 3, 'C')
,(4, 4, 'D')
,(5, 5, 'F')
CREATE TABLE TABLE2 (ID INT, TPRICE INT, TPRODUCT CHAR(1))
INSERT INTO Table2 (ID,TPRICE,TPRODUCT) VALUES
(1, 1, 'A')
,(2, 2, 'B')
,(3, 3, 'C')
,(4, 5, 'D')
,(6, 6, 'E')
SELECT *
FROM Table1 t1
FULL JOIN
Table2 t2 ON t1.ID = t2.ID
--EDIT: remove to exactly match the desired output
--OR t1.FPRICE = t2.TPRICE
--OR t1.FPRODUCT = t2.TPRODUCT
WHERE NOT ( t1.ID = t2.ID
AND t1.FPRICE = t2.TPRICE
AND t1.FPRODUCT = t2.TPRODUCT)
OR ( COALESCE(t1.ID,t1.FPRICE,T1.FPRODUCT) IS NULL
OR COALESCE(t2.ID,t2.TPRICE,T2.TPRODUCT) IS NULL)

Use full join:
select *
from Table1 t1
full join Table2 t2 on t1.ID = t2.ID and
t1.FPRICE = t2.FPRICE /*and
t1.FPRODUCT = t2.FPRODUCT*/
where t1.ID is null or t2.ID is null

It looks like you want to match on the id's and then compare the values:
select t1.id, t1.fprice, t1.fproduct, t2.fprice, t2.fproduct
from Table1 t1 full join
Table2 t2
on t1.ID = t2.ID
where (t1.ID is null or t2.ID is null) or -- no match as all
(t1.FPRICE <> t2.FPRICE or
t1.FPRODUCT <> t2.FPRODUCT
);
The where clause is a bit more complicated if the column values could be NULL, but your sample data does not have any examples of NULLs.

SELECT *
FROM Table1 t1
FULL JOIN Table2 t2 ON t2.ID = t1.ID
WHERE
t2.TPRICE <> t1.FPRICE
OR t2.TPRODUCT <> t1.FPRODUCT
OR t2.TPRICE IS NULL
OR t1.FPRICE IS NULL
OR t2.TPRODUCT IS NULL
OR t1.FPRODUCT IS NULL

Can you try this query?
SELECT DISTINCT t1.ID t1.FPRICE t1.FPRODUCT
from Table1 t1 LEFT JOIN Table2 ON
Table1.ID = Table2.ID AND Table1.FPRICE = Table2.TPRICE AND Table1.FPRODUCT= Table2.TPRODUCT
WHERE
Table1.ID is NULL or Table1.FPRICE is NULL or Table1.FPRODUCT is NULL
or Table2.TPRICE is NULL or Table2.TPRODUCT is NULL

I would format the answer from Michael1105 as:
SELECT ISNULL(t1.ID,t2.ID),t1.FPRICE,t1.FPRODUCT,t2.TPRICE,t2.TPRODUCT FROM Table_1 t1 FULL JOIN Table_2 t2 ON t2.ID = t1.ID WHERE t2.TPRICE
<>t1.FPRICE OR t2.TPRODUCT
<>t1.FPRODUCT OR t2.TPRICE IS NULL OR t1.FPRICE IS NULL OR t2.TPRODUCT IS NULL OR t1.FPRODUCT IS NULL
for your exact requirement.

Related

Pivot data using multiple join

I have a table like this in SQL Server
name
tems
aver
a
1
12
a
2
13.5
b
1
19
b
2
15.5
c
2
5
d
1
16.75
How should I have following form with join clause? Not with group by, CTE, COALESCE, Null functions, conditional aggregation and PIVOT. Case clause in only allowed in join conditions.
select columns
from Table T1
join Table T2 on .......................
join Table T3 on .......................
name
aver1
aver2
a
12
13.5
b
19
15.5
b
Null
5
d
16.75
Null
I would recommend conditional aggregation:
select name,
max(case when tems = 1 then aver end) as aver1,
max(case when tems = 2 then aver end) as aver2
from mytable
group by name
If you insist on joining, then:
select t1.name, t1.aver as aver1, t2.aver as aver2
from mytable t1
inner join mytable t2 on t2.name = t1.name
and t1.tems = 1 and t2.tems = 2
One caveat with the above join technique is that it eliminates names that do not have both tems, so it would not produce the result you want for your sample data. You could work around this with a full join, but that would incur additional complexity. The conditional aggregation is simpler.
..for join...
declare #t table(name varchar(10), tems smallint, aver decimal(9,2));
insert into #t(name, tems, aver)
values
('a', 1, 12),
('a', 2, 13.5),
('b', 1, 19),
('b', 2, 15.5),
('c', 2, 5),
('d', 1, 16.75);
select coalesce(t1.name, t2.name) as name, t1.aver as aver1, t2.aver as aver2
from
(
select *
from #t
where tems = 1
) as t1
full outer join
(
select *
from #t
where tems = 2
) as t2 on t1.name = t2.name;
select coalesce(t1.name, t2.name) as name, t1.aver as aver1, t2.aver as aver2
from #t as t1
full outer join #t as t2 on t1.name = t2.name and t1.tems = 1 and t2.tems = 2
where t1.tems = 1
or
(t1.tems is null and t2.tems=2);
select t3.name, t1.aver as aver1, t2.aver as aver2
from #t as t1
full outer join #t as t2 on t1.name = t2.name and t1.tems = 1 and t2.tems = 2
join #t as t3 on case when t1.name is null then t2.name else t1.name end = t3.name
and case when t1.name is null then 2 else 1 end = t3.tems
where t1.tems = 1
or
t1.tems is null and t2.tems=2;

MS SQL not exist where more columns are

I have table 1 from which I need take and ad to table2 only rows which is not in table 2
Table 1
ID Name N T
A Bob 33 Y
B Eva 44 N
C John 47 Y
B Alex 44 N
D Bob 47 Y
Table 2
ID Name N T
A Bob 34 Y
B Alex 44 N
D Bob 47 Y
I try set up this type of version script but i get duplicity of whole table 1 + new rows
INSERT INTO TABLE_2
(ID , Name , N , T)
SELECT table1.ID, table1.Name, table1.N, table1.T
FROM TABLE_1 table1
WHERE NOT EXISTS(SELECT 1
FROM TABLE_2 table2
WHERE (table2.ID = table1.ID) and (table2.Name = table1.Name) and (table2.N = table1.N )AND (table2.T = table1.T))
Expect Result
A Bob 34 Y
B Alex 44 N
D Bob 47 Y
A Bob 33 Y
B Eva 44 N
C John 47 Y
One approach would be to an INSERT INTO ... SELECT with a select query identifying all records in table1 which do not completely match some record in table2.
INSERT INTO table2 (ID, Name, N, T)
SELECT t1.ID, t1.Name, t1.N, t1.T
FROM table1 t1
LEFT JOIN table2 t2
ON t1.ID = t2.ID AND
t1.Name = t2.Name AND
t1.N = t2.N AND
t1.T = t2.T
WHERE t2.ID IS NULL
Note that the logic here is that if even one column of a given record in table1 be not in agreement with a certain record in table2, then the join would fail, and all table2 columns would then come up NULL in the result set. The WHERE clause restricts to only such non matching records in table1.
You could join both tables with a left join.
All records from Table_1 who don't have a match with Table_2 have to be inserted. To check which record doesn't have a match you can simply use T2.ID IS NULL
INSERT INTO TABLE_2 (ID , Name , N , T)
SELECT T1.ID
,T1.Name
,T1.N
,T1.T
FROM TABLE_1 T1
LEFT JOIN TABLE_2 T2
ON T1.ID = T2.ID
AND T1.Name = T2.Name
AND T1.N = T2.N
AND T1.T = T2.T
WHERE T2.ID IS NULL
declare #Table1 table (ID varchar(100), Name varchar(100), N int, T varchar(100));
insert into #Table1 values
('A', 'Bob', 33, 'Y'),
('B', 'Eva', 44, 'N'),
('C', 'John', 47, 'Y'),
('B', 'Alex', 44, 'N'),
('D', 'Bob', 47, 'Y')
declare #Table2 table (ID varchar(100), Name varchar(100), N int, T varchar(100));
insert into #Table2 values
('A', 'Bob', 34, 'Y'),
('B', 'Alex', 44, 'N'),
('D', 'Bob', 47, 'Y')
insert into #Table2
select *
from #Table1 t1
where not exists (select *
from #Table2 t2
where t2.ID = t1.ID and t2.N= t1.N and t2.Name = t1.Name and t1.T = t2.T);

SQL (oracle) Update some records in table A using values in table B

I have to tables :
Table1
--------------------------------
ID VAL1 DATE1
--------------------------------
1 1 20/03/2015
2 null null
3 1 10/01/2015
4 0 12/02/2015
5 null null
Table2
--------------------------------
ID VAL2 DATE1
--------------------------------
1 N 02/06/2015
2 null null
3 O 05/04/2015
4 O 01/07/2015
5 O 03/02/2015
I want to update :
column VAL1 of Table1 with '0', if VAL2 of Table2 is equal to 'O'
column DATE1 of Table1 with DATE2 of Table2
(This two tables are not so simple, it's just for illustration, they can be joined with the ID column).
So the expected result is :
Table1
--------------------------------
ID VAL1 DATE1
--------------------------------
1 1 20/03/2015
2 null null
3 0 05/04/2015
4 0 01/07/2015
5 0 03/02/2015
Here my code :
UPDATE Table1 t1
SET t1.VAL1 = '0',
SET t1.DATE1 = (SELECT t2.DATE2 from Table2 t2
INNER JOIN Table1 t1
ON trim(t2.ID)=trim(t1.ID))
WHERE EXISTS (SELECT NULL
FROM Table2 t2
WHERE trim(t2.ID) = trim(t1.ID)
AND t2.Table2 = 'O');
The part that make my code not working is : (esle working)
SET t1.DATE1 = (SELECT t2.DATE2 from Table2 t2
INNER JOIN Table1 t1
ON trim(t2.ID)=trim(t1.ID))
You want a correlated subquery, not a join in the subquery. So, assuming the rest of the logic is correct:
UPDATE Table1 t1
SET t1.VAL1 = '0',
t1.DATE1 = (SELECT t2.DATE2
FROM Table2 t2
WHERE trim(t2.ID) = trim(t1.ID))
WHERE EXISTS (SELECT 1
FROM Table2 t2
WHERE trim(t2.ID) = trim(t1.ID) AND
t2.Table2 = 'O'
);

Get groups that are exactly equal to a table

I have a query that groups easily. I need to get the groups that have exactly the same records to another table (relationship).
I'm using ANSI-SQL under SQL Server, but I accept an answer of any implementation.
For example:
Table1:
Id | Value
---+------
1 | 1
1 | 2
1 | 3
2 | 4
3 | 2
4 | 3
Table2:
Value | ...
------+------
1 | ...
2 | ...
3 | ...
In my example, the result is:
Id |
---+
1 |
How imagined that it could be the code:
SELECT Table1.Id
FROM Table1
GROUP BY Table1.Id
HAVING ...? -- The group that has exactly the same elements of Table2
Thanks in advance!
You can try the following:
select t1.Id
from Table2 t2
join Table1 t1 on t1.value = t2.value
group by t1.Id
having count(distinct t1.value) = (select count(*) from Table2)
SQLFiddle
To get the same sets use an inner join:
SELECT Table1.Id
FROM Table1
INNER JOIN table2 ON table1.id=table2.id
GROUP BY Table1.Id
HAVING ...? --
CREATE TABLE #T1 (ID INT , [Values] INT) INSERT INTO #T1 VALUES (1,1),(1,2),(1,3),(2,4),(2,5),(3,6)
CREATE TABLE #T2 ([Values] INT) INSERT INTO #T2 VALUES (1),(2),(3),(4)
SELECT * FROM #T1
SELECT * FROM #T2
SELECT A.ID
FROM
( SELECT ID , COUNT(DISTINCT [Values]) AS Count FROM #T1
GROUP BY ID
) A
JOIN
(
SELECT T1.ID, COUNT(DISTINCT T2.[Values]) Count
FROM #T1 T1
JOIN #t2 T2
ON T1.[Values] = T2.[Values]
GROUP BY T1.ID
) B
ON A.ID = B.ID AND A.Count = B.Count

Best practices for multi table join query

Tables structure are below :
Table1 (ID int, value1 int,...)
ID Value1
---- --------
1 10
2 20
5 12
Table2 (ID int, value2 int,...)
ID Value2
---- --------
1 13
3 24
4 11
Table3 (ID int, value3 int,...)
ID Value3
---- --------
4 150
5 100
My expected output is below.
ID Value1 Value2 Value3
---- -------- -------- --------
1 10 13 NULL
2 20 NULL NULL
3 NULL 24 NULL
4 NULL 11 150
5 12 NULL 100
It should be noted that above tables is huge and I want to have best performance.
My query suggestion is below :
Select ID,
SUM(Value1) AS Value1,
SUM(Value2) AS Value2,
SUM(Value3) AS Value3
From (
Select ID, Value1 , NULL as value2, NULL as value 3
From Table1
Union ALL
Select ID, NULL , value2, NULL
From Table2
Union ALL
Select ID, NULL, NULL, value 3
From Table3
)Z
Group By Z.ID
Assuming you only have one value per id, this should do the trick:
SELECT aux.ID, t1.Value1, t2.Value2, t3.Value3
FROM
(SELECT ID FROM Table1
UNION
select ID FROM Table2
UNION
SELECT ID FROM Table3) aux
LEFT OUTER JOIN Table1 t1 ON aux.ID = t1.ID
LEFT OUTER JOIN Table2 t2 ON aux.ID = t2.ID
LEFT OUTER JOIN Table3 t3 ON aux.ID = t3.ID
If you've more than one value:
SELECT aux.ID, SUM(t1.Value1) as 'Value1', SUM(t2.Value2) as 'Value2', SUM(t3.Value3) as 'Value3'
FROM
(SELECT ID FROM Table1
UNION
select ID FROM Table2
UNION
SELECT ID FROM Table3) aux
LEFT OUTER JOIN Table1 t1 ON aux.ID = t1.ID
LEFT OUTER JOIN Table2 t2 ON aux.ID = t2.ID
LEFT OUTER JOIN Table3 t3 ON aux.ID = t3.ID
GROUP BY aux.ID
I intially wrote the same answer as aF. did above. So, removed it, and used a different approach.
Here,
1st query get all from table1
2nd query gets all from table2 skipping
those already present in table1 3rd query gets all remaining skipping those in above two query.
SELECT T1.ID, T1.VALUE1, T2.VALUE2, T3.VALUE3 --all T1
FROM TABLE1 T1
LEFT JOIN TABLE2 ON T1.ID=T2.ID
LEFT JOIN TABLE3 ON T1.ID=T3.ID
UNION
SELECT T2.ID, T1.VALUE1, T2.VALUE2, T3.VALUE3 --all T2 where T1 is NULL
FROM TABLE1 T2
LEFT JOIN TABLE1 ON T2.ID=T1.ID
LEFT JOIN TABLE3 ON T2.ID=T3.ID
WHERE T1.ID IS NULL
UNION
SELECT T3.ID, T1.VALUE1, T2.VALUE2, T3.VALUE3 --all T3 where T1 is NULL AND T2 IS NUL
FROM TABLE1 T3
LEFT JOIN TABLE1 ON T3.ID=T1.ID
LEFT JOIN TABLE2 ON T3.ID=T2.ID
WHERE T1.ID IS NULL
AND T2.ID IS NULL