how to write a efficient to get the difference from two table - sql

hi i am using SQL Server 2008, want to create a view to list the different between two tables.
for example
t1
id name
---- ------
1 John
2 peter
3 mary
4 joe
5 sun
t2
id name
--- ----
1 john
2 joe
how to create a view to list all the name in t1 but not in t2.
i tried to do that, and always get
"Conversion failed when converting from a character string to uniqueidentifier."
error
and also, i don`t want to use
select something not in {something}, this is slow
so is there any way can use join??

NOT IN
SELECT t1.name
FROM TABLE_1 t1
WHERE t1.name NOT IN (SELECT t2.name
FROM TABLE_2 t2)
NOT EXISTS
SELECT t1.name
FROM TABLE_1 t1
WHERE NOT EXISTS (SELECT NULL
FROM TABLE_2 t2
WHERE t2.name = t1.name)
LEFT JOIN/IS NULL:
SELECT t1.name
FROM TABLE_1 t1
LEFT JOIN TABLE_2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL
Summary
Contrary to your belief, NOT IN will perform equivalent to NOT EXISTS. LEFT JOIN/IS NULL is the least efficient of the three options.

Here's a trick I use:
SELECT MAX(TABLE_NAME) AS TABLE_NAME
,[id]
,[name]
FROM (
SELECT 'T1' AS TABLE_NAME
,[id]
,[name]
FROM T1
UNION ALL
SELECT 'T2' AS TABLE_NAME
,[id]
,[name]
FROM T2
) AS X
GROUP BY [id]
,[name]
HAVING COUNT(*) = 1
ORDER BY [id]
,[name]
I actually have a universal proc I use which takes two tables and a bunch of parameters and does table compares generating dynamic SQL (the SQL above is actually cleaned up code-generated output of it), it uses either this UNION ALL trick or a combination of the three joins in OMG Ponies' answer depending on whether key columns/ignore columns/comare columns are specified.

SELECT name FROM TABLE_1
EXCEPT
SELECT name FROM TABLE_2

Related

Fectch uncommon ID between two columns

I have two tables and I need to fetch if any one ID is not present in the table 2. I tried the query but its not giving the correct result. Kindly suggest.
TABLE 1
TABLE 2
Output Should be: Because Release ID and purchase ID is not present in both the columns.
QUERY Tried :
SELECT T1_ID
FROM T1 LEFT OUTER JOIN T2
ON t1.RELEASEID=t2.RELEASEID
LEFT OUTER JOIN T2 t3
ON t1.PURCHASEID=t3.PURCHASEID
WHERE IFNULL(T2.RELEASEID,'') ='' OR IFNULL(T3.PURCHASEID,'')=''
You can use NOT EXISTS as follows:
select * from t1
where not exists (select 1 from t2
where t1.releaseid =t2.releaseid or t1.purchaseid =t2.purchaseid)
You can also use LEFT JOIN as follows:
select t1.*
from t1 left join t2
on t1.releaseid =t2.releaseid or t1.purchaseid =t2.purchaseid
where t2.t2_id is null
One method is not exists:
select t1.*
from t1
where not exists (select 1
from t2
where t2.releaseid = t1.releaseid
) and
not exists (select 1
from t2
where t2.purchaseid = t1.purchaseid
);
This should work regardless of whether ? is really a string or is supposed to represent NULL.
Note: This can take advantage of indexes on t2(releaseid) and t2(purchaseid), which can be a big boost to performance on larger data.
I think you want:
select t1.*
from table1 t1
where
(t1.release_id = '?' and t2.purchase_id = '?')
or not exists (
select 1
from table2 t2
where t1.release_id in ('?', t2.release_id)
and t1.purchase_id in ('?', t2.purchase_id)
)
If the question mark is supposed to represent null values, you can just replace all instances of = '?' with is null.
Please try this and let me know if it works.
SELECT * FROM TABLE1 WHERE NOT EXISTS (SELECT '1' FROM TABLE2 WHERE TABLE1 .RELEASEID=TABLE2.RELEASEID OR TABLE1 .PURCHASEID=TABLE2.PURCHASEID);

Compare two tables and give the output record which does not exist in 1st table

I want an SQL code which should perform the task of data scrubbing.
I have two tables both contain some names I want to compare them and list out only those name which are in table 2 but not in table 1.
Example:
Table 1 = A ,B,C
Table 2 = C,D,E
The result must have D and E?
SELECT t2.name
FROM 2 t2
LEFT JOIN
1 t1 ON t1.name=t2.name
WHERE t1.name IS NULL
select T2.Name
from Table2 as T2
where not exists (select * from Table1 as T1 where T1.Name = T2.Name)
See this article about performance of different implementations of anti-join (for SQL Server).
select t2.name
from t2,t1
where t2.name<>t1.name -- ( or t2.name!=t1.name)
If the DBMS supports it:
select name from table2
minus
select name from table1
A more portable solution could also be:
select name from table2
where name not in (select name from table1)

SQL nested query

I have a table like below
id name dependency
-----------------------
1 xxxx 0
2 yyyy 1
3 zzzz 2
4 aaaaaa 0
5 bbbbbb 4
6 cccccc 5
the list goes on. I want to select group of rows from this table , by giving the name of 0 dependency in where clause of SQL and till it reaches a condition where there is no more dependency. (For ex. rows 1,2, 3 forms a group, and rows 4,5,6 is another group) .please help
Since you did not specify a product, I'll go with features available in the SQL specification. In this case, I'm using a common-table expression which are supported by many database products including SQL Server 2005+ and Oracle (but not MySQL):
With MyDependents As
(
Select id, name, 0 As level
From MyTable
Where dependency = 0
And name = 'some value'
Union All
Select T.id, T.name, T.Level + 1
From MyDependents As D
Join MyTable As T
On T.id = D.dependency
)
Select id, name, level
From MyDependents
Another solution which does not rely on common-table expressions but does assume a maximum level of depth (in this case two levels below level 0) would something like
Select T1.id, T1.name, 0 As level
From MyTable As T1
Where T1.name = 'some value'
Union All
Select T2.id, T2.name, 1
From MyTable As T1
Join MyTable As T2
On T2.Id = T1.Dependency
Where T1.name = 'some value'
Union All
Select T3.id, T3.name, 2
From MyTable As T1
Join MyTable As T2
On T2.Id = T1.Dependency
Join MyTable As T3
On T3.Id = T2.Dependency
Where T1.name = 'some value'
Sounds like you want to recursively query your table, for which you will need a Common Table Expression (CTE)
This MSDN article explains CTEs very well. They are confusing at first but surprisingly easy to implement.
BTW this is obviously only for SQL Server, I'm not sure how you'd achieve that in MySQL.
This is the first thing that came to mind. It can be probably done more directly/succinctly, I'll try to dwell on it a little.
SELECT *
FROM table T1
WHERE T1.id >=
(SELECT T2.id FROM table T2 WHERE T2.name = '---NAME HERE---')
AND T1.id <
(SELECT MIN(id)
FROM table T3
WHERE T3.dependency = 0 AND T3.id > T2.id)
If you can estimate a max depth, this works out to something like:
SELECT
COALESCE(t4.field1, t3.field1, t2.field1, t1.field1, t.field1),
COALESCE(t4.field2, t3.field2, t2.field2, t1.field2, t.field2),
COALESCE(t4.field3, t3.field3, t2.field3, t1.field3, t.field3),
....
FROM table AS t
LEFT JOIN table AS t1 ON t.dependency = t1.id
LEFT JOIN table AS t2 ON t1.dependency = t2.id
LEFT JOIN table AS t3 ON t2.dependency = t3.id
LEFT JOIN table AS t4 ON t3.dependency = t4.id
....
This is a wild guess just to be different, but I think it's kind of pretty, anyway. And it's at least as portable as any of the others. But I don't want to look to closely; I'd want to use sensible data, start testing, and check for sensible results.
Hierarchical query will do:
SELECT *
FROM your_table
START WITH id = :id_of_group_header_row
CONNECT BY dependency = PRIOR id
Query works like this:
1. select all rows satisfying START WITH condition (this rows are roots now)
2. select all rows satisfying CONNECT BY condition,
keyword PRIOR means this column's value will be taken from the root row
3. consider rows selected on step 2 to be roots
4. go to step 2 until there are no more rows

Get list of duplicate rows in MySql

i have a table like this
ID nachname vorname
1 john doe
2 john doe
3 jim doe
4 Michael Knight
I need a query that will return all the fields (select *) from the records that have the same nachname and vorname (in this case, records 1 and 2).
Can anyone help me with this? Thanks
The following query will give the list of duplicates :
SELECT n1.* FROM table n1
inner join table n2 on n2.vorname=n1.vorname and n2.nachname=n1.nachname
where n1.id <> n2.id
BTW The data you posted seems to be wrong "Doe" and "Knight" are a lastname, not a firstname :p.
The general solution to your problem is a query of the form
SELECT col1, col2, count(*)
FROM t1
GROUP BY col1, col2
HAVING count(*) > 1
This will return one row for each set of duplicate row in the table. The last column in this result is the number of duplicates for the particular values.
If you really want the ID, try something like this:
SELECT id FROM
t1,
( SELECT col1, col2, count(*)
FROM t1
GROUP BY col1, col2
HAVING count(*) > 1 ) as t2
WHERE t1.col1 = t2.col1 AND t1.col2 = t2.col2
Haven't tested it though
You can do it with a self-join:
select distinct t1.id from t as t1 inner join t as t2
on t1.col1=t2.col1 and t1.col2=t2.col2 and t1.id<>t2.id
the t1.id<>t2.id is necessary to avoid ids matching against themselves. (If you want only 1 row out of each set of duplicates, you can use t1.id<t2.id).
select * from table AS t1 inner join
(select max(id) As id,nachname,vorname, count(*)
from t1 group by nachname,vorname
having count(*) >1) AS t2 on t1.id=t2.id
This should return ALL of the columns from the table where there is duplicate nachname and vorname. I recommend changing * to the exact columns that you need.
Edit: I added a max(id) so that the group by wouldn't be a problem. My query isn't as elegant as I would want though. There's probably an easier way to do it.

mysql - union tables by unique field

I have two tables with the same structure:
id name
1 Merry
2 Mike
and
id name
1 Mike
2 Alis
I need to union second table to first with keeping unique names, so that result is:
id name
1 Merry
2 Mike
3 Alis
Is it possible to do this with MySQL query, without using php script?
This is not a join (set multiplication), this is a union (set addition).
SELECT #r := #r + 1 AS id, name
FROM (
SELECT #r := 0
) vars,
(
SELECT name
FROM table1
UNION
SELECT name
FROM table2
) q
This will select all names from table1 and combine those with all the names from table2 which are not in table1.
(
select *
from table1
)
union
(
select *
from table2 t2
left join table1 t1 on t2.name = t1.name
where t1.id is null
)
Use:
SELECT a.id,
a.name
FROM TABLE_A a
UNION
SELECT b.id,
b.name
FROM TABLE_B b
UNION will remove duplicates.
As commented, it all depends on what your 'id' means, cause in the example, it means nothing.
SELECT DISTINCT(name) FROM t1 JOIN t2 ON something
if you only want the names
SELECT SUM(something), name FROM t1 JOIN t2 ON something GROUP BY name
if you want to do some group by
SELECT DISTINCT(name) FROM t1 JOIN t2 ON t1.id = t2.id
if the id's are the same
SELECT DISTINCT COALESCE(t1.name,t2.name) FROM
mytable t1 LEFT JOIN mytable t2 ON (t1.name=t2.name);
will get you a list of unique names from the 2 tables. If you want them to get new ids (like Alis does in your desired results), that's something else and requires the answers to a couple of questions:
do any of the names need to maintain their previous id. And if they do, which table's id should be preferred?
why do you have 2 tables with the same structure? ie what are you trying to accomplish when you generate the unique name list?