Counting the number of rows which do not match - sql

I have two tables with exactly the same structure i.e. same columns. I want to find out number of rows which exist in both tables but do not have exactly the same matching values for all columns. E.g. Table has colums Id, Name, Country. Id is the primary key. If Id=1 exists in both tables then other values should also match. Currently, I am using this kind of statement.
SELECT COUNT(*)
FROM ##Table1 t1 ,
##Table2 t2
WHERE t1.Id = t2.Id
AND ( t1.Name != t2.name
OR t1.Country != t2.Country
)
Table has too many columns hence this is becoming too unwieldly. Is there a better way to do it?

SELECT COUNT(*)
FROM ##Table1 t1
JOIN ##Table2 t2
ON t1.Id = t2.Id
AND EXISTS (SELECT t1.*
EXCEPT
SELECT t2.*)
SQL Fiddle

Perhaps you can concatenate the columns into a single field and check for equality that way?

Related

How to select data from the table not exist in another table sql

How to select data from the table not exist in another table sql. I've tried NOT IN and NOT EXIST methods. But it causes performance issues for large amount of data. Can anyone suggest a solution for this.?
Thanks in advance.
I’ve tried the following.
SELECT name
FROM table1
WHERE NOT EXISTS
(SELECT *
FROM table2
WHERE table1.name = table2.name)
And NOT IN Cases.
But performance issues while a for large number of data.
I think your table table1 and table2 have index on their name column, so you can try this:
SELECT name
FROM table1 t1 LEFT JOIN table2 t2 ON t1.name = t2.name
WHERE t2.id IS NULL
May be id column existed, if not, use t2.name as a replacement for t2.id
For this query:
SELECT name
FROM table1
WHERE NOT EXISTS
(SELECT *
FROM table2
WHERE table1.name = table2.name)
You want an index on table2(name).

SQL select rows based on 2 col criteria in a separate table

I wish to select some rows from a table based on values from another table:
Table1 (wish to select from here)
Columns Date, Name, Pay
Table2 (contains a 'list' that determines what is selected from Table1)
Columns Date, Name
The query I wish to write is to:
Select Date,Name,Pay from Table1 where Date,Name is present in Table2
I got as far as being able to do it on one value
SELECT Date,Name,Pay FROM Table1 WHERE Table1.Name IN (Select Table2.name from Table2)
but Im stuck with how to add the date qualifier. The names in either table are not unique, what makes them unique is the date and name combination.
If I understood your question clearly, you want to apply join
select t1.Date,t1.Name,t1.Pay FROM Table1 t1 inner join Table2 t2
ON t1.Name = t2.Name and t1.Date = t2.Date
The generic SQL solution uses exists:
Select Date, Name, Pay
from Table1 t1
where exists (select 1 from table2 t2 where t2.date = t1.date and t2.name = t1.name);
This will not match values in table 2 if they are NULL. For that, you would need a NULL-safe comparison operation. The ANSI standard is is not distinct from.
Some databases support in with tuples. In those databases, you can write:
Select Date, Name, Pay
from Table1 t1
where (t1.date, t1.name) in (select t2.date, t2.name from table2 t2);
Once again, this might have an issue with NULL values, depending on how you want to treat them.
Interestingly, you could extend your logic by using a correlated subquery:
SELECT Date, Name, Pay
FROM Table1 t1
WHERE t1.Name IN (Select t2.name from Table2 t2 where t2.date = t1.date);
Although this does what you want, I think the previous two approaches are clearer in their intent.
I should note that you could use a join for this. However, that would return duplicate values if you had duplicates in table2. For that reason, I prefer the exists or in methods, because these have no risk of duplicating values.
You can use alias (and instead of subquery a join ) for a more easy vision of your related table
SELECT a.Date, a.Name, a.Pay
FROM Table1 a
inner join Table2 b on a.name = b.name
in this case date is obtain from table1, changing the alias or addingi both column if you need more

Select all from one table where some columns match another select

I have two differents tables. The have some columns in common, for this example lets say 'name' and 'id'.
By making
( SELECT name,id FROM table1
EXCEPT
SELECT name,id FROM table2)
UNION ALL
( SELECT name,id FROM table2
EXCEPT
SELECT name,id FROM table1)
I get a list of the elements that are on one tablet but not in the other one.
Up to this point everything is OK.
But now, I want to make a select all from table1 where the name and the id matches the result of the query above.
After lots of comments I think this is what you're after...
SELECT T1.*
FROM table1 t1
LEFT JOIN table2 t2
on T1.ID = T2.ID
and T1.Name = T2.Name
AND E2.event_Time_UTC between convert(datetime,'2016-02-09 00:00:20',101) and convert(datetime '2016-02-09 23:59:52',101)
WHERE T2.Name is null
AND E1.Event_Time_UTC between convert(datetime,'2016-02-09 00:00:20',101) and convert(datetime,'2016-02-09 23:59:52',101)
You may allow implicit casting to work but above is the explicit approach.
If not then you would need to cast the string dates to a date time, assuming Event_Time_UTC is a date/time datatype.
A left join lets us return all records from the 1st table and only those that match from the 2nd.
The t1.* returns only the columns from table1. The join criteria (on) allows us to identify those records which match so they can then be eliminated in the where clause by 'where t2.name is null' they will always be null when no record match in t2.
Thus you get a result set that is: all records from t1 without a matching record on name and id in table2.
Old version
The below content is no longer relevant, based on comments.
I redacted previous answer a lot because you're using SQL Server not MySQL and I know you want multiple records not table1 and table2 joined.
In the below I create two tables: table1 and table2. I then populate table1 and table2 with some sample data
I then show how to get only those records which exist in one table but not the other; returning a separate ROW for each. I then go into detail as to why I choose this approach vs others. I'll finally review what you've tried and try to explain why I don't think it will work.
create table table1 (
ID int,
name varchar(20),
col1 varchar(20),
col2 varchar(20),
col3 varchar(20));
Create table table2 (
id int,
name varchar(20));
Insert into table1 values (1,'John','col1','col2','col3');
Insert into table1 values (2,'Paul','col1','col2','col3');
Insert into table1 values (3,'George','col1','col2','col3');
Insert into table2 values (1,'John');
Insert into table2 values (4,'Ringo');
Option 1
SELECT T1.name, T1.ID, T1.Col1, T1.Col2, T1.Col3
FROM Table1 T1
LEFT JOIN Table2 T2
on T1.Name = T2.Name
and T1.ID = T2.ID
WHERE T2.ID is null
UNION ALL
SELECT T2.name, T2.ID, NULL, NULL, NULL
FROM Table1 T1
RIGHT JOIN Table2 T2
on T1.Name = T2.Name
and T1.ID = T2.ID
WHERE T1.ID is null ;
which results in...
Notice John isn't there as it's in both tables. We have the other 2 records from table1, and the ID, name from table2 you're after.
Normally I would do this as a full outer join but since I think you want to reuse the name and id fields to relate to BOTH tables in the same column we had to use this approach and spell out all the column names in table 1 and put NULL for each column in table1 when displaying records from table2 in order to make the output of the second query union to the first. We simply can't use *
Option 2: Using a full outer join... with all columns from T1
SELECT T1.*
FROM Table1 T1
FULL OUTER JOIN Table2 T2
on T1.ID = T2.ID
and T1.Name = T2.Name
WHERE (T1.ID is null or T2.ID is null)
you get this... which doesn't show Ringo...
But then I would ask why you need anything from Table 2 at all so I think you're wanting to still show the ID, Name from table2 when it doesn't exist in table1.
Which is why What I think you're after is the results from the 1st query using the union all.
Option 3 I suppose we could avoid the second query in option 1 by doing...
SELECT coalesce(T1.Name, T2.name) as name, coalesce(T1.Id,T2.ID) as ID, T1.col1, T1.Col2, T1.Col3
FROM Table1 T1
FULL OUTER JOIN Table2 T2
on T1.ID = T2.ID
and T1.Name = T2.Name
WHERE (T1.ID is null or T2.ID is null)
which gives us what I believe to be the desired results as well.
This works because we know we only want the name,id from table2 and all the column values in table1 will be blank.
Notice however in all cases we simply can't use Tablename.* to select all records from table1.
This is what you tried:
( SELECT name,id FROM table1
EXCEPT
SELECT name,id FROM table2)
UNION ALL
( SELECT name,id FROM table2
EXCEPT
SELECT name,id FROM table1)
Assuming you want to reuse the ID, Name fields; you can't select *. Why? because the records in Table2 not in table1 aren't in table1. In my example if you want Ringo to show up you have to reference table2! Additionally, * gives you no ability to "Coalesce" the ID and name fields together as I did in option 3 above.
If you ONLY want the columns from table1, that means you will NEVER see data from table2. If you don't need the data from table2, (such as ringo in my example) then why do we need to do the union at all?) I'm assuming you want ringo, thus you HAVE to somewhere reference name, id from table2.
You could also do this with NOT EXISTS:
SELECT *
FROM table1
WHERE
NOT EXISTS
(SELECT 1
FROM table2
WHERE table1.id = table2.id
AND table1.name = table2.name)
;with cte as
(
( SELECT name,id FROM table1
EXCEPT
SELECT name,id FROM table2)
UNION ALL
( SELECT name,id FROM table2
EXCEPT
SELECT name,id FROM table1)
)
Select *
from table1 as tbl1
where
tbl1.id = cte.id
and tbl1.name = cte.name

SQL query to find empty values with complex condition

I have primary table (table1 - contains customer main information) that is related to another table (table2 - contains customer contact information) and common value is ID.
In primary table the ID value gives me 1 row, another table may gives me more rows, depending on how many contact types the customer has, for example:
main_phone (this row always exists)
home_phone
work_phone
mobile etc.
What I am trying to achieve:
First I want to check mobile value, if row is missing or there is no mobile value, but row exists then I want to check main_phone value.
But if there is mobile value then I don't want to check the main_phone value.
If main_phone value also missing then I want these records.
Currently I have query:
Select customer
From table1 t1
Join table2 t2 on t1.id = t2.id
Where t2.type in (main_phone, mobile)
And t2.type_values in ('',null,'-')
but the problem is, if customers has mobile number and missing phone number, these client records also show up in the result.
this might get you close..
SELECT customer
FROM table1 t1
WHERE NOT EXISTS (
SELECT 1
FROM table2 t2
WHERE t1.id = t2.id
AND t2.type in (main_phone, mobile)
and ISNULL(t2.type_value,'') NOT IN ('','-')
)
if it finds a value in the NOT EXISTS query it will be excluded
You have to be careful and treat null as a special value. The two queries below will return different results.
Select COUNT(*) from table1 t1
join table2 t2 on t1.id=t2.id
where t2.type in (main_phone, mobile)
and t2.type_values in ('',null,'-')
Select COUNT(*) from table1 t1
join table2 t2 on t1.id=t2.id
where t2.type in (main_phone, mobile)
and (t2.type_values IS NULL) OR(t2.type_values in ('','-'))
You should get in the habit of testing for null using a null comparison such as X IS NULL, NOT X IS NULL, ISNULL() or COALESCE().
did you want something like this?
SELECT
customer
FROM
table1 t1 JOIN
(SELECT
id
FROM
table1 t1 JOIN
table2 t2 ON
t1.id=t2.id
WHERE
t2.TYPE = mobile AND
(t2.type_values IS NULL OR
t2.type_values IN ('','-') )) missing_mobile ON
t1.id = missing_mobile.id
WHERE
t2.TYPE = main_phone AND
(t2.type_values IS NULL OR
t2.type_values IN ('','-') )

Adding rows of one table to rows of another table where two tables are matched by ID

In an Access 2013 database, I have a table t1 and another table t2. They both have the same number of columns and column names are also the same. Table t2 have a number of overlaps with id variable of table t1. I am trying to make a new table t3 where I add all the rows of t1 and only those rows of t2 that are not matched by an id variable present in both the tables t1 and t2. I used something like
Create Table t3 As Select * From (Select t1.* From t1 Inner Join t2 on t1.ID_Number = t2. ID_Number)
This throws syntax error. However, even if it worked this will select those rows that matches ID_Number in both the tables. I have tried various other codes and browsed through many other relevant stackoverflow post but could not resolve it.
try this :
SELECT t1.*
INTO t3
FROM t1
INNER JOIN t2
ON t1.ID_Number = t2.ID_Number
I am not sure about Access syntax but can this 2-step solution work?
select t1.* into t3 from t1 where t1.ID_Number not in (select t2.ID_Number from t2)
select t2.* into t3 from t2 where t2.ID_Number not in (select t1.ID_Number from t1)