Excel SQL - Compare Values - sql

My first post here and looking for some help on how to compare values in 2 tables and bring back a list of the differences
This is to be done in excel via VBA, I tried a few different ways like Full join and Union but can't get it to run.
Basic Scenario is this:
Table A has 2 columns,
Column 1 = ID
Column 2 = Qty
Exact same set up in Table B
What i want to do is gather a list where the Qty is different or doesn't appear in either table
e.g.
Table A has
ID 1
Qty 3
Table B has
ID 1
Qty 2
So it would bring back one of the records
Or
Table A has ID 5 and Table B doesn't
Table B has ID 7 and Table A doesn't
Not sure on the best method to do this, i know i can do it in excel via a formula but trying to accomplish in SQL if possible
Thanks

From a SQL perspective you will be looking at two different statements:
ID and Qty combination are in A, but not B
ID and Qty combination are in B, but not A
This will look something like:
SELECT tableA.id, tableA.qty FROM tableA LEFT JOIN tableB on tableA.id = tableB.id and tableA.qty = tableB.qty WHERE tableB.qty IS NULL
SELECT tableB.id, tableB.qty FROM tableB LEFT JOIN tableA on tableBid = tableA.id and tableB.qty = tableA.qty WHERE tableA.qty IS NULL
You can union these two together to get a single statement of mismatched records like so:
SELECT tableA.id, tableA.qty FROM tableA LEFT JOIN tableB on tableA.id = tableB.id and tableA.qty = tableB.qty WHERE tableB.qty IS NULL
UNION ALL
SELECT tableB.id, tableB.qty FROM tableB LEFT JOIN tableA on tableBid = tableA.id and tableB.qty = tableA.qty WHERE tableA.qty IS NULL
And you can add a reason to each individual SQL statement so you know why the mismatch happened:
SELECT tableA.id,
tableA.qty,
"Item in Table A, but not Table B" as Reason
FROM tableA
LEFT JOIN tableB
ON tableA.id = tableB.id
AND tableA.qty = tableB.qty
WHERE tableB.qty IS NULL
UNION ALL
SELECT tableB.id,
tableB.qty,
"Item in Table B, but not Table A" as Reason
FROM tableB
LEFT JOIN tableA
ON tableBid = tableA.id
AND tableB.qty = tableA.qty
WHERE tableA.qty IS NULL

Related

Full Outer Join failing to return all records from both tables

I have a pair of tables I need to join, I want to return any record that's in tableA, tableB or both. I think I need a FULL OUTER JOIN
This query return 1164 records
SELECT name FROM tableA
WHERE reportDay = '2022-Apr-05'
And this one return 3339 records
SELECT name FROM tableB
WHERE reportDay = '2022-Apr-05'
And this one returns 3369 records (so there must be 30 records in tableA that aren't in tableB)
select distinct name FROM tableA where reportDay = '2022-Apr-05'
union distinct
select distinct name FROM tableB where reportDay = '2022-Apr-05'
I want to obtain a list of all matching records in either table. The query above returns 3369 records, so a FULL OUTER JOIN should also return 3369 rows (I think). My best effort so far is shown below. It returns 1164 rows and returns what looks to me to be a left join between tableA and tableB.
SELECT tableA.name.*, tableB.name.*
FROM tableA
FULL OUTER JOIN tableB
ON (tableA.name = tableB.name and tableB.reportDay = '2022-Apr-05')
WHERE tableA.reportDay = '2022-Apr-05'
Help appreciated. (if this looks question looks familiar, it's a follow-on question to this one )
UPDATE - Sorry (#forpas) to keep moving the goalposts - I'm trying to match test data to real-data scenario's.
DROP TABLE tableA;
DROP TABLE tableB;
CREATE TABLE tableA (name VARCHAR(10),
reportDay DATE,
val1 INTEGER,
val2 INTEGER);
CREATE TABLE tableB (name VARCHAR(10),
reportDay DATE,
test1 INTEGER,
test2 INTEGER);
INSERT INTO tableA values ('A','2022-Apr-05',1,2),
('B','2022-Apr-05',3,4), ('C','2022-Apr-05',5,6),
('A','2022-Apr-06',1,2), ('B','2022-Apr-06',3,4),
('C','2022-Apr-06',5,6), ('Z','2022-Apr-04',5,6),
('Z','2022-Apr-06',5,6) ;
INSERT INTO tableB values ('A','2022-Apr-03',5,6),
('B','2022-Apr-04',11,22), ('B','2022-Apr-05',11,22),
('C','2022-Apr-05',33,44), ('D','2022-Apr-05',55,66),
('B','2022-Apr-06',11,22), ('C','2022-Apr-06',33,44),
('D','2022-Apr-06',55,66), ('Q','2022-Apr-06',5,6);
SELECT tableA.*, tableB.*
FROM tableA
FULL OUTER JOIN tableB
ON (tableA.name = tableB.name and tableB.reportDay = '2022-Apr-05'
AND tableA.reportDay = '2022-Apr-05' )
For this data, I'd hope to see 4 rows of data 'A' from tableA only, 'B' and 'C' from both tables, and 'D' from table B only. I'm after the 5th April records only! The query (shown above) suggested by #forpas works except that the 'A' record in tableA doesn't get returned.
UPDATE - FINAL EDIT AND ANSWER!
Ok, the solution seem to be to concetenate the two fields together before joining....
SELECT a.*, b.*
FROM tableA a FULL OUTER JOIN tableB b
ON (b.name || b.reportDay) = (a.name || a.reportDay)
WHERE (a.reportDay = '2022-Apr-05' OR a.reportDay IS NULL)
AND (b.reportDay = '2022-Apr-05' OR b.reportDay IS NULL);
The condition for the date should be placed in a WHERE clause:
SELECT a.*, b.*
FROM tableA a FULL OUTER JOIN tableB b
ON b.name = a.name AND a.reportDay = b.reportDay
WHERE '2022-Apr-05' IN (a.reportDay, b.reportDay);
or:
SELECT a.*, b.*
FROM tableA a FULL OUTER JOIN tableB b
ON b.name = a.name
WHERE (a.reportDay = '2022-Apr-05' OR a.reportDay IS NULL)
AND (b.reportDay = '2022-Apr-05' OR b.reportDay IS NULL);
See the demo.

SQL Multiple joins with OR condition

I have a following tables:
TableA
id
name
TableB
id
tableA_id
TableC
id
tableA_id
So tables B and C have tableA_id fk.
I need a query which will return all id-s from TableA that have reference in either TableB or TableC.
If I do standard join, it will return only values that have reference in both tables B and C.
I could do this using two queries, one joins B, other joins C and use UNION to merge results, but I dont want to write same query twice.
Is there a way to achieve this 'OR' JOIN??
Try with this
SELECT DISTINCT TABLEA.ID_A, TABLEA.NAME
FROM TABLEA,TABLEB,TABLEC
WHERE TABLEA.ID_A = TABLEB.ID_A AND TABLEA.ID_A = TABLEC.ID_A
Using DISTINCT TAG you eliminate duplicates.
Something like this?
SELECT
*
FROM
TableA,
TableB,
TableC
WHERE
TableA.id = TableB.tableA_id
OR TableA.id = TableC.tableA_id
You can use left outer joins and checks for the ids:
SELECT a.id FROM A a
LEFT JOIN B b ON a.id = b.tableA_id LEFT JOIN C c ON a.id = c.tableA_id
WHERE b.id IS NOT NULL OR c.id IS NOT NULL

sql left join clarification

I have two tables.
I need all records from table A except where there is a match in table B, then take table B's matching value
So if table A has a match with table B, then I need to exclude that value from the results (i.e take all records from table A and replace records from table A with the matching value from table B).
from my understanding I left joined the two tables on the matching column and then added a where clause to exclude the null values but I'm not sure if that is correct.
data:
tableA (col1 =ID, col2 =value)
1, 5
2, 3
3, 7
tableB (col1 =ID, col2 =value)
4, 6
2, 9
expected result:
5
9
7
This is the closest I've gotten but I'm not sure if it's correct:
select * from tableA tblA
left join tableB tblB
on tblA.matchingColumn = tblB.matchingColumn
where tblB.matchingColumn is null
This will return all the rows in TABLEA. If there are any matching value in TABLEB then it will be used as VALUE.
SELECT TBLA.ID
, COALESCE(TBLB.VALUE, TBLA.VALUE) VALUE
FROM TABLEA TBLA
LEFT JOIN TABLEB TBLB
ON TBLA.ID = TBLB.ID;
UPDATE - SQLFiddle for this thread
Perform a left join from tablea to tableb and use the value from a or b depending on match in tableb
select tablea.id, case when tableb.id is null then tablea.value else tableb.value end value
from tablea
left join tableb on tablea.id=tableb.id

SQL - not sure how to join tables

I'm trying to join two tables like this:
Table A
ID Value1
1 A
2 B
3 C
Table B
ID Value2
1 A
3 B
4 C
Result should be:
ID Value1 Value2
1 A A
2 B null
3 C B
4 null C
I.e. join Table A to Table B on ID. If ID doesn't exist in Table A, add the ID from Table B.
The closest I've come is:
SELECT
a.ID, a.Value1, b.Value2
FROM
TableA a
OUTER JOIN
TableB b ON a.ID = b.ID
That gives me the new rows from TableB, but the ID is null.
How can I accomplish this?
You are very close, you just need a little push in the right direction:
SELECT COALESCE(a.ID, B.ID) As ID, a.Value1, b.Value2
FROM TableA a
FULL OUTER JOIN TableB b ON a.ID=b.ID
The COALESCE function returns the first parameter it gets that is not null. since this is a full outer join, a.id will be null on one row and b.id would be null on a different row.
Try this:
SELECT *
FROM TableA A
FULL OUTER JOIN TableB B
ON A.ID = B.ID;
Just a note: you should not name your tables in SQL with spaces in them.
Remember the basic for joining different tables
SELECT column_name(s)
FROM table1
FULL OUTER JOIN table2
ON table1.column_name=table2.column_name;
For your case:
SELECT a.value1, b.value2
FROM TableA a
FULL OUTER JOIN TableB b ON a.ID=b.ID
remember full outer join
The FULL OUTER JOIN keyword returns all rows from the table (tableA) and from the table (tableB) and the FULL OUTER JOIN keyword combines the result of both LEFT and RIGHT joins.

Sorting data from one table based on another table

Here are my tables:
create table tableA (id int, type varchar(5))
insert into tableA (ID,TYPE)
values
(101,'A'),
(101,'C'),
(101,'D'),
(102,'A'),
(102,'B'),
(103,'A'),
(103,'C')
create table tableB (id int, type varchar(5), isActive bit)
insert into tableB (id, type, isActive)
Values
(101,'A',1),
(101,'B',0),
(101,'C',0),
(101,'D',1),
(102,'A',1),
(102,'B',0),
(102,'C',1),
(102,'D',1),
(103,'A',1),
(103,'B',1),
(103,'C',1),
(103,'D',1)
Now, I want to do two things here:
1) Find the rows that are present in tableA but isActive = 0 in tableB. (done)
select A.* from tableA A
join tableB B
on A.id = B.id and A.type = B.type
where B.isactive = 0
2) Find the rows that are missing in tableA but isActive = 1 in tableB.
For example ID 103, type B is active in tableB but is missing in tableA.
I don't care about existance of type D in tableA because I am only checking the last entry in tableA which is C.
Also, ABCD is in order for all IDs, they can be active or inactive.
Thanks for your help!
My effort: (not working)
select A.* from tableA A
where exists (
select B.* from tableA A
join tableB B
on a.id = b.id
where b.isActive = 1
order by b.id,b.type
)
SQLFiddle
I think you are looking for something like the following:
select B.* from tableB B
left join tableA A
on B.id = A.id and B.type = A.type
where B.isActive = 1
and A.id is null
order by B.id, B.type
By using the left join, it means that rows in tableB that have no rows to join with in tableA will have all A.* columns null. This then allows you to add the where clause to check where the tableA records are null thus determining what is contained within tableB that is active and not in tableA