query to select non matching records from two tables - sql

I have 2 tables like this:
Table Student_Old:
id name city
1 A X
2 B Y
3 C Z
Table Student_new:
id name city
1 A X
2 M Y
3 C K
As you can see for Id 2,name is mismatching and for Id 3, city is mismatching in both tables(I am doing comparison on ID which is primary key in both table, basically student_new is backup table for old ). Now I want to get these 2 rows which are not matching.
e.g:
student_old s1, student_new s2-
s1.id s2.id s1.name s2.name s1.city s2.city
2 2 B M X X
3 3 C C Z K

Since you don't care about records which are in one table but not in the other, a simple JOIN will suffice:
SELECT s1.id AS old_id, s2.id AS new_id,
s1.name AS old_name, s2.name AS new_name,
s1.city AS old_city, s2.city AS new_city
FROM student_old s1
JOIN student_new s2
ON s1.id = s2.id
WHERE s1.name != s2.name OR s1.city != s2.city
Output:
old_id new_id old_name new_name old_city new_city
2 2 B M Y Y
3 3 C C Z K

SELECT so.id AS id_1, so.name AS name_1, so.city AS city_1,
sn.id AS id_2, sn.name AS name_2, sn.city AS city_2
FROM student_old so
INNER JOIN student_new sn
ON so.id = sn.id
WHERE so.name <> sn.name AND so.city <> sn.city

use join
select os.*,ns.* Student_Old os join Student_new ns on os.id=ns.id
where os.city!=ns.city OR os.name!=ns.name

Use inner join and where clause do filter out non matching name and city
select a.* , b.* from Student_Old inner join Student_new
on a.id=b.id
where a.name<>b.name or a.city<>b.city

Related

Select multiple count(*) in multiple tables with single query

I have 3 tables:
Basic
id
name
description
2
Name1
description2
3
Name2
description3
LinkA
id
linkA_ID
2
344
3
3221
2
6642
3
2312
2
323
LinkB
id
linkB_ID
2
8287
3
42466
2
616422
3
531
2
2555
2
8592
3
1122
2
33345
I want to get results as the table below:
id
name
description
linkA_count
linkB_count
2
Name1
description2
3
2
3
Name2
description3
5
3
my query:
SELECT
a.id
,a.name
,a.description
,COUNT(b.linkA_ID) AS linkA_count
,COUNT(c.linkB_ID) AS linkb_count
FROM
basic a
JOIN linkA b on (a.id = b.id)
JOIN linkb c on (a.id = c.id)
GROUP BY
a.id
,a.name
,a.description
Result from the query is count of linkA always same as linkB
A more traditional approach is to use "derived tables" (subqueries) so that the counts are performed before joins multiply the rows. Using left joins allows for all id's in basic to be returned by the query even if there are no related rows in either joined tables.
select
basic.id
, coalesce(a.LinkACount,0) LinkACount
, coalesce(b.linkBCount,0) linkBCount
from basic
left join (
select id, Count(linkA_ID) LinkACount from LinkA group by id
) as a on a.id=basic.id
left join (
select id, Count(linkB_ID) LinkBCount from LinkB group by id
) as b on b.id=basic.id
Try This (using SubQuery)
SELECT
basic.id
,basic.name
,basic.description
,(select Count(linkA_ID) from LinkA where LinkA.id=basic.id) as LinkACount
,(select Count(linkB_ID) from LinkB where LinkB.id=basic.id) as LinkBCount FROM basic
Method 2 (Try CTE)
with a as(select id,Count(linkA_ID)LinkACount from LinkA group by id)
, b as (select id,Count(linkB_ID)LinkBCount from LinkB group by id)
select basic.id,a.LinkACount,b.linkBCount
from basic
join a on (a.id=basic.id)
join b on (b.id=basic.id)
If you only select from your table you see why your query cannot work.
SELECT
*
FROM
basic a
JOIN linkA b on (a.id = b.id)
JOIN linkb c on (a.id = c.id)
WHERE a.ID = 3
=> just use distinct in your count
SELECT
a.id
,a.name
,a.description
,COUNT(DISTINCT(b.linkA_ID)) AS linkA_count
,COUNT(DISTINCT(c.linkB_ID)) AS linkb_count
FROM
basic a
JOIN linkA b on (a.id = b.id)
JOIN linkb c on (a.id = c.id)
GROUP BY
a.id
,a.name
,a.description

Is there a way to join two queries in SQL each with an order by?

I have two queries that return data from two tables:
SELECT TOP 3
AE.id, AE.name, COUNT(R.id) 'number of reserves'
FROM
AIRPORT AE
INNER JOIN
FLY V ON V.id_destiny = AE.id
INNER JOIN
RESERVE R ON R.id_fly = V.id
GROUP BY
AE.id, AE.name
ORDER BY
COUNT(R.id) DESC;
Example of returned data:
id
name
number of reserves
6
name1
27
4
name2
18
14
name3
14
and
SELECT TOP 3
AE.id, AE.name, COUNT(R.id) 'number of reserves'
FROM
AEROPUERTO AE
LEFT JOIN
FLY V ON V.id_destiny = AE.id
LEFT JOIN
RESERVE R ON R.id_fly = V.id
GROUP BY
AE.id, AE.name
ORDER BY
COUNT(R.id) ASC;
Example of data returned from this second query:
id
name
number of reserves
7
name4
0
11
name5
0
12
name6
0
I need to combine these into a single output with the first query first (in the same order) and the second query next with the same order like this:
id
name
number of reserves
6
name1
27
4
name2
18
14
name3
14
7
name4
0
11
name5
0
12
name6
0
Is there a way to do it?
Edit: I have already tried the union all option, but I can't use the group by in each query so the table that is returned is different from what I need
(SELECT TOP 3 AE.id, AE.name, COUNT(R.id) 'number of reserves'
FROM AIRPORT AE
INNER JOIN FLY V
ON V.id_destiny = AE.id
INNER JOIN RESERVE R
ON R.id_fly = V.id
GROUP BY AE.id, AE.name)
UNION ALL
(SELECT TOP 3 AE.id, AE.name, COUNT(R.id) 'number of reserves'
FROM AEROPUERTO AE
LEFT JOIN FLY V
ON V.id_destiny= AE.id
LEFT JOIN RESERVE R
ON R.id_fly = V.id
GROUP BY AE.id, AE.name)
ORDER BY COUNT(R.id) ASC;
When you enclosed each query in parenthesis, it is acting like a derived table. You will need a SELECT clause to select from the derived table.
SELECT *
FROM
(
-- Your first query here
) AS Q1
UNION ALL
SELECT *
FROM
(
-- Your second query here
) AS Q2
You may also use CTE to do it
WITH
Q1 AS
(
-- Your first query here
),
Q2 AS
(
-- Your second query here
)
SELECT *
FROM Q1
UNION ALL
SELECT *
FROm Q2
EDIT : if you also wanted the final result in the same order in both query, add another column for final query ORDER BY
WITH
Q1 AS
(
SELECT TOP 3
AE.id, AE.name, COUNT(R.id) 'number of reserves',
Q = 1,
RN = ROW_NUMBER() OVER (ORDER BY COUNT(R.id) DESC)
FROM
AIRPORT AE
INNER JOIN
FLY V ON V.id_destiny = AE.id
INNER JOIN
RESERVE R ON R.id_fly = V.id
GROUP BY
AE.id, AE.name
ORDER BY
COUNT(R.id) DESC
),
Q2 AS
(
SELECT TOP 3
AE.id, AE.name, COUNT(R.id) 'number of reserves',
Q = 2,
RN = ROW_NUMBER() OVER (ORDER BY COUNT(R.id) DESC)
FROM
AEROPUERTO AE
LEFT JOIN
FLY V ON V.id_destiny = AE.id
LEFT JOIN
RESERVE R ON R.id_fly = V.id
GROUP BY
AE.id, AE.name
ORDER BY
COUNT(R.id) ASC
)
SELECT *
FROM Q1
UNION ALL
SELECT *
FROM Q2
ORDER BY Q, RN
I break the query and made two temp tables. You can do this in CTE (Commn Table expression) as well.
SELECT TOP 3 AE.id, AE.name, COUNT(R.id) 'number of reserves'
INTO #Temp_1
FROM AIRPORT AE
INNER JOIN FLY V
ON V.id_destiny = AE.id
INNER JOIN RESERVE R
ON R.id_fly = V.id
GROUP BY AE.id, AE.name
SELECT TOP 3 AE.id, AE.name, COUNT(R.id) 'number of reserves'
into #Temp_2
FROM AEROPUERTO AE
LEFT JOIN FLY V
ON V.id_destiny= AE.id
LEFT JOIN RESERVE R
ON R.id_fly = V.id
GROUP BY AE.id, AE.nam
SELECT *
FROM #Temp_1
UNION ALL
SELECT *
FROM #Temp_2
drop table #Temp_1
drop table #Temp_2

Removing string from sql

Please see below data..
Table A
AID NAME
1 A
2 B
3 C
4 D
5 E
6 F
Table B
BID AID NAME
1 1 T1
2 1 T2
3 2 T3
4 2 T4
5 3 T5
6 4 T6
7 1 T7
8 1 T8
9 2 T9
10 2 T10
11 3 T11
12 4 T12
I am using this statement
SELECT
dbo.A.NAME AS ANAME, dbo.B.NAME AS BNAME
FROM
dbo.A
LEFT OUTER JOIN
dbo.B ON dbo.A.AID = dbo.B.AID
Its returning these results:
ANAME BNAME
A T1
A T2
A T7
A T8
B T3
B T4
B T9
B T10
C T5
C T11
D T6
D T12
E NULL
F NULL
but I need following result
ANAME BNAME
A T1
T2
T7
T8
B T3
T4
T9
T10
C T5
T11
D T6
T12
E NULL
F NULL
How to remove extra names from above?
Try this
SELECT CASE WHEN ROW_NUMBER() OVER ( PARTITION BY A.NAME ORDER BY A.NAME ) = 1
THEN A.NAME
ELSE ''
END AS ANAME ,
dbo.B.NAME AS BNAME
FROM dbo.A
LEFT OUTER JOIN dbo.B ON dbo.A.AID = dbo.B.AID;
I guess something like the following could be done if absolutely needed to do in SQL, seeing as it is presentation.
SELECT CASE WHEN ROW_NUMBER() OVER ( PARTITION BY A.AID ORDER BY A.AID ) > 1
THEN ''
ELSE A.NAME
END AS ANAME ,
dbo.B.NAME AS BNAME
FROM dbo.A
LEFT OUTER JOIN dbo.B ON dbo.A.AID = dbo.B.AID;
You can use below SQL query to get your desired output:
SELECT (CASE WHEN SrNo = 1
THEN ANAME
ELSE ''
END) AS ANAME
, BNAME
FROM (
SELECT ROW_NUMBER OVER (PARTITION BY dbo.A.NAME ORDER BY dbo.B.NAME) AS SrNo,
dbo.A.NAME AS ANAME, dbo.B.NAME AS BNAME
FROM dbo.A LEFT OUTER JOIN
dbo.B ON dbo.A.AID = dbo.B.AID
) AS tbl

Sql Query to find sum from different tables

Hi i require a help in writing a query.
Tables are:
tblStandard1students
tblStandard2students
tblStandard1students
tblDivision
tblCandidateinfo
tblStandard1students,tblStandard2students,tblStandard1studentstbl contain information about students enrolled in standard 1,2 and 3
tblStandars1students
Candid admitted
1 Y
2 N
3 Y
tblDivision contains only 2 columns
ID Division
1 A
2 B
3 C
tblCandidateinfo
Candid gender Division
1 M 1
2 F 2
and so on...
Now I want the table like this
Division Students(Standard1) Students(Standard2) Students(Standard3)
M F M F M F
------------------------------------------------------------------------
A 1 0 0 0 0 1
B 2 2 3 3 4 4
C 1 0 0 0 0 0
I tried this following query:
SELECT Division,
( SELECT count(*)
FROM tblStandard1students A
INNER JOIN tblCandidateinfo B ON A.Candid=B.Candid
INNER JOIN tblDivision C ON C.ID=B.Division) AS Students(Standard1),
( SELECT count(*)
FROM tblStandard2students A
INNER JOIN tblCandidateinfo B ON A.Candid=B.Candid
INNER JOIN tblDivision C ON C.ID=B.Division) AS Students(Standard2),
( SELECT count(*)
FROM tblStandard3students A
INNER JOIN tblCandidateinfo B ON A.Candid=B.Candid
INNER JOIN tblDivision C ON C.ID=B.Division ) AS Students(Standard3)
FROM tblDivision Z
but this is only half the query i din segregate it gender wise...help me to complete it.
;WITH combined AS
(
SELECT ci.Division, 'Students(Standard1) ' + ci.gender AS grp
FROM tblCandidateInfo ci
INNER JOIN tblStandard1students s ON ci.Candid = s.Candid
UNION ALL
SELECT ci.Division, 'Students(Standard2) ' + ci.gender AS grp
FROM tblCandidateInfo ci
INNER JOIN tblStandard2students s ON ci.Candid = s.Candid
UNION ALL
SELECT ci.Division, 'Students(Standard3) ' + ci.gender AS grp
FROM tblCandidateInfo ci
INNER JOIN tblStandard1studentstbl s ON ci.Candid = s.Candid
)
SELECT Division,
[Students(Standard1) M], [Students(Standard1) F],
[Students(Standard2) M], [Students(Standard2) F],
[Students(Standard3) M], [Students(Standard3) F]
FROM
(
SELECT d.Division, grp
FROM tblDivision d
LEFT OUTER JOIN combined c ON d.ID = c.Division
) x
PIVOT
(
COUNT(grp)
FOR grp IN ([Students(Standard1) M], [Students(Standard1) F],
[Students(Standard2) M], [Students(Standard2) F],
[Students(Standard3) M], [Students(Standard3) F])
) y
ORDER BY Division
SELECT divison.Division ,IFNULL(stander1.M,0),IFNULL(stander1.F,0) FROM test.tblDivision divison
Left join (SELECT division ,count( case gender when 'M' then 1 else null end) as M,count( case gender when 'F' then 1 else null end) as F
FROM
test.tblCandidateinfo tc inner join test.tblStandars1students ts1
ON tc.Candid=ts1.Candid
group by division) as stander1 on stander1.division= divison.id
group by divison.id
;
Insted of IFNULL use ISNULL and
take left join for all standar tables

I have a table "Student", now I would like to query the result as same as the second table. One group must have 2 students.

I have a table Student, now I would like to query the result the same as the second table. One group must have 2 students.
Student ID Name Gender Group
1 A M A1
2 B F A1
3 C M A2
4 D M A2
5 E F A3
6 F F A3
Name1 Gender1 Name2 Gender2 Group
A M B F A1
C M D M A2
E F F F A3
Something like:
select t1.name, t1.gender, t2.name, t2.gender, t1.group
from student t1, student t2
where t1.group = t2.group and t1.id < t2.id
Here is the complete example.
CREATE TABLE testing
(id char(10),
name char(10),
gender char(1),
grp char(10))
insert into testing values ('1','A','M','A1')
insert into testing values ('2','B','F','A1')
insert into testing values ('3','C','M','A2')
insert into testing values ('4','D','M','A2')
insert into testing values ('5','E','F','A3')
insert into testing values ('6','F','F','A3')
select name1, gender1, name2, gender2, a.grp from
(
SELECT name1 = CASE CONVERT(int,id)%2 WHEN 1 THEN name ELSE null END,
gender1 = CASE CONVERT(int,id)%2 WHEN 1 THEN gender ELSE null END,
grp FROM testing where CONVERT(int,id)%2 =1
) a
left join
(
SELECT name2 = CASE CONVERT(int,id)%2 WHEN 0 THEN name ELSE null END,
gender2 = CASE CONVERT(int,id)%2 WHEN 0 THEN gender ELSE null END,
grp FROM testing where CONVERT(int,id)%2 =0
) b on a.grp=b.grp
SELECT s1.name AS Name1, s1.gender AS Gender1,
s2.name AS Name2, s2.gender AS Gender2,
groups.group_s
FROM (
SELECT MIN(id) AS st_first, MAX(id) AS st_second, group_s
FROM students
GROUP BY group_s
) AS groups
LEFT JOIN students s1 ON groups.st_first=s1.id
LEFT JOIN students s2 ON groups.st_second=s2.id
students is the name of your table and group_s is the group column