Compare Column(data) from different table and view in SQL Developer - sql

I would like to compare few columns in different view with table.
For example:
View a:
student_id First_Name University high_degree
0011221 Tom New York university Y
0011221 Tom MIT N
0011222 Peter Harvard university Y
0011223 Sam Northeastern university Y
0011224 Leo Boston university Y
0011225 Paul Boston college Y (this is not correct)
0011225 Paul Tufts N
table b:
student_id First_Name University degree
0011221 Tom New York university MS
0011222 Peter Harvard university DR
0011223 Sam Northeastern university BS
0011224 Leo Boston university BS
0011225 Paul Tufts DR
Assume that the table b is the most update student information, but in the view a it is the old data from different old table and some student fill the wrong information, then I want to find out which students's information is incorrect.
For example Paul studied two school, Boston college for BS, Tufts for Doctor. In table B is the most update student info, Paul studied Tufts that is the high degree. However in view a Paul's high degree is Boston college so this is wrong information. I am looking for which student has same situation. how to do that?
Ideal result like:
student_id First_Name University high_degree result
0011221 Tom New York university Y match
0011221 Tom MIT N null
0011222 Peter Harvard university Y match
0011223 Sam Northeastern university Y match
0011224 Leo Boston university Y match
0011225 Paul Boston college N null
0011225 Paul Tufts Y not match
No need to same with ideal result, but just need to know which student in view a has different data by comparing with table b.
I appreciate your reply. thank you so much.

One option is to use outer join, while result is retrieved by case expression.
Sample data:
SQL> with
2 view_a (first_name, university, high_degree) as
3 (select 'Tom' , 'New York university', 'Y' from dual union all
4 select 'Tom' , 'MIT' , 'N' from dual union all
5 select 'Peter', 'Harvard university' , 'Y' from dual union all
6 select 'Paul' , 'Boston college' , 'Y' from dual union all
7 select 'Paul' , 'Tufts' , 'N' from dual
8 ),
9 table_b (first_name, university) as
10 (select 'Tom' , 'New York university' from dual union all
11 select 'Peter', 'Harvard university' from dual union all
12 select 'Paul' , 'Tufts' from dual
13 )
Query:
14 select a.first_name, a.university, a.high_degree,
15 case when a.university = b.university then
16 case when a.high_degree = 'Y' then 'Match'
17 when a.high_degree = 'N' then 'Not match'
18 end
19 else null
20 end result
21 from view_a a left join table_b b on a.first_name = b.first_name
22 and a.university = b.university
23 order by a.first_name desc, a.university;
FIRST UNIVERSITY HIGH_DEGREE RESULT
----- ------------------- ------------ ---------
Tom MIT N
Tom New York university Y Match
Peter Harvard university Y Match
Paul Boston college Y
Paul Tufts N Not match
SQL>

Related

Select unique countries with more than one customer

I need to show the countries that have more than one individual.
Customers
customer_id first_name last_name age country
1 John Doe 31 USA
2 Robert Luna 22 USA
3 David Robinson 22 UK
4 John Reinhardt 25 UK
5 Betty Doe 28 UAE
So the query should return
customer_id first_name last_name age country
1 John Doe 31 USA
2 Robert Luna 22 USA
3 David Robinson 22 UK
4 John Reinhardt 25 UK
I tried tis query but it didn't work.
SELECT last_name, Country
FROM Customers
GROUP BY Country
HAVING COUNT(Customer_id) > 1;
The actual table can be found here
Try using the following query. Thanks
SELECT * FROM CUSTOMERS C
WHERE C.COUNTRY IN (SELECT COUNTRY FROM CUSTOMERS GROUP BY COUNTRY HAVING COUNT(*)>1)
You could use a windowed count as a filter:
with c as (
select *, Count(*) over(partition by country) cnt
from Customers
)
select *
from c
where cnt > 1;

Show mapping based on student access

There is a table which has following data:
student subject code
student1 maths 312
student1 physics 785
student2 english 900
student3 geography 317
I am trying to restrict access to each student in the table to view data specific to their chosen subject. But there is one restriction to show maths data to student2. Thereby both student1 and student2 both would be able to see maths data, and this mapping has to be done without altering the master data. So only while displaying the table, student2 should be mapped to both english and maths.
Thanks for the help here!
One option is to - as you said - temporarily use UNION set operator. Something like this:
SQL> WITH
2 test (student, subject, code)
3 AS
4 (SELECT 'student1', 'maths', 312 FROM DUAL
5 UNION ALL
6 SELECT 'student1', 'physics', 785 FROM DUAL
7 UNION ALL
8 SELECT 'student2', 'english', 900 FROM DUAL
9 UNION ALL
10 SELECT 'student3', 'geography', 317 FROM DUAL)
11 SELECT *
12 FROM test
13 WHERE student = '&&par_student'
14 -- add this to your query
15 UNION
16 SELECT 'student2', 'maths', NULL
17 FROM DUAL
18 WHERE '&&par_student' = 'student2';
Enter value for par_student: student1 --> student1 is OK, it has two subjects
STUDENT SUBJECT CODE
-------- --------- ----------
student1 maths 312
student1 physics 785
SQL> undefine par_student
SQL> /
Enter value for par_student: student2 --> for student2, UNION is used
STUDENT SUBJECT CODE
-------- --------- ----------
student2 english 900
student2 maths
SQL> undefine par_student
SQL> /
Enter value for par_student: student3 --> nothing new for student3
STUDENT SUBJECT CODE
-------- --------- ----------
student3 geography 317
SQL>
Depending on tool you use, parameter might look as this (in e.g. TOAD):
WHERE student = :par_student
or any other way parameters are used in that tool of yours.
Something like:
SELECT student, subject, code
FROM (
SELECT t.*,
COUNT(
CASE
WHEN student = :your_student
OR (:your_student, subject) IN (('student2', 'maths'))
THEN 1
END
) OVER (PARTITION BY subject) AS has_access
FROM table_name t
)
WHERE has_access > 0
Then, for the sample data:
CREATE TABLE table_name (student, subject, code) AS
SELECT 'student1', 'maths', 312 FROM DUAL UNION ALL
SELECT 'student1', 'physics', 785 FROM DUAL UNION ALL
SELECT 'student2', 'english', 900 FROM DUAL UNION ALL
SELECT 'student3', 'geography', 317 FROM DUAL;
If :your_student is student1 then the output is:
STUDENT
SUBJECT
CODE
student1
maths
312
student1
physics
785
and if :your_student is student2 then the output is:
STUDENT
SUBJECT
CODE
student2
english
900
student1
maths
312
db<>fiddle here

How do I display rows from a max count?

I want to return all the data, from max count query with hospital that has most number of patients. What I seem to be getting when I try to nest queries is display of all rows of hospital data. I've tried to look at similar questions in stack overflow and other sites it seems to be a simple query to do but i am not getting it.
select max(highest_hospital) as max_hospital
from (select count(hospital) as highest_hospital
from doctor
group by hospital)
highest_hospital
-------------
3
Doc ID Doctor Patient Hospital Medicine Cost
------ ------- ------ --------- ------ --------
1 Jim Bob Patient1 Town 1 Medicine 1 4000
2 Janice Smith Patient2 Town 2 Medicine 3 3000
3 Harold Brown Patient3 Town 2 Medicine 5 2000
4 Larry Owens Patient4 Town 2 Medicine 6 3000
5 Sally Brown Patient5 Town 3 Medicine 7 4000
6 Bob Jim Patient6 Town 4 Medicine 8 6000
Outcome should be return of 3 rows
Doc ID Doctor Patient Hospital Medicine Cost
------ ------- ------ --------- ------ --------
2 Janice Smith Patient2 Town 2 Medicine 3 3000
3 Harold Brown Patient3 Town 2 Medicine 5 2000
4 Larry Owens Patient4 Town 2 Medicine 6 3000
You can use window functions:
select d.*
from (select d.*, max(hospital_count) over () as max_hospital_count
from (select d.*, count(*) over (partition by hospital) as hospital_count
from doctor d
) d
) d
where hospital_count = max_hospital_count;
Edit:
Using GROUP BY is a pain. If you are only looking for a single hospital (even when there are ties), then in Oracle 12C you can do:
select d.*
from doctor d
where d.hospital = (select d2.hospital
from doctor d2
group by d2.hospital
order by count(*) desc
fetch first 1 row only
);
You can do this in earlier versions of Oracle using an additional subquery.

Adding a new column that auto increments based on existing field values

Not sure how to do this, but I want to add a new column "Jersey" that will increment by 1 depending on the "Sport" value in both tab_A and tab_B. So if a "Sport" already exists in tab_B, then just grab the max jersey_no and add 1 for the new column. That one is easy.
Now if the "Sport" does not exist in tab_B, then give it a "Jersey" value of 100 for the new column. However, if there is more than one of the same "Sport" in tab_A (but do not exist in tab_B), then it should start with 100 and increment by 1 for the next same Sport, and so on (e.g. see Garcia example below).
I created a sequence "seqnce" but, that really didn't help at all. Is there another way to accomplish this? Thanks in advance!
Tab_A
Name State Sport
Garcia CA Basketball
Garcia AL Basketball
Garcia NY Basketball
McGee CA Swimming
Tontou CA Football
Tontou AL Swimming
Tab_B
Name Sport Jersey_No
Garcia Swimming 100
Garcia Football 100
McGee Swimming 101
Tontou Swimming 101
Tontou Swimming 102
Expected Output
Name State Sport Jersey
Garcia CA Basketball 100
Garcia AL Basketball 101
Garcia NY Basketball 102
McGee CA Swimming 102
Tontou CA Football 100
Tontou AL Swimming 103
My Code
select name, state, sport
,nvl ((select max(b.jersey_no + 1) from tab_b b
where b.sport = a.sport
and b.name = a.name),
(case
when not exists (select 1 from tab_b b
where b.sport = a.sport
and b.name = a.name
having count(a.sport) > 1)
then seqnce.nextval
else '100'
end )
) Jersey
from tab_a
If it's only select result then using row_number(). If you need update column in table, then write trigger
Example this:
WITH taba AS
(SELECT 'Garcia' Name, 'CA' State, 'Basketball' Sport from dual
UNION ALL
SELECT 'Garcia' Name, 'AL' State, 'Basketball' Sport from dual
UNION ALL
SELECT 'Garcia' Name, 'NY' State, 'Basketball' Sport from dual
UNION ALL
SELECT 'McGee' Name, 'CA' State, 'Swimming' Sport from dual
UNION ALL
SELECT 'Tontou' Name, 'CA' State, 'Football' Sport from dual
UNION ALL
SELECT 'Tontou' Name, 'AL' State, 'Swimming' Sport from dual),
tabb AS
(SELECT 'Garcia' Name, 'Swimming' Sport, 100 Jersey from dual
UNION ALL
SELECT 'Garcia' Name, 'Football', 100 from dual
UNION ALL
SELECT 'McGee' Name, 'Swimming', 101 from dual
UNION ALL
SELECT 'Tontou' Name, 'Swimming', 101 from dual
UNION ALL
SELECT 'Tontou' Name, 'Swimming', 102 from dual)
SELECT taba.Name,
taba.State ,
taba.Sport,
row_number() over(partition by taba.Name, taba.Sport ORDER BY taba.State)
+ nvl((SELECT MAX(tabb.Jersey)
FROM tabb
WHERE taba.name = tabb.name
AND taba.sport = tabb.sport), 99)
FROM taba
result:
Garcia AL Basketball 100
Garcia CA Basketball 101
Garcia NY Basketball 102
McGee CA Swimming 102
Tontou CA Football 100
Tontou AL Swimming 103

HIVE Get male and female count who opted for any course

I have two tables, students and training. Student and Training tables are as below.
Student
ID name age sex salary
1213 lavanya 18 Female 8000
1208 reshma 19 Female 14000
1207 bhavya 20 Female 15000
1212 Arshad 28 Male 20000
1209 kranthi 22 Male 22000
1210 Satish 24 Male 25000
1211 Krishna 25 Male 26000
1203 khaleel 34 Male 30000
1204 prasant 30 Male 31000
1206 laxmi 25 Female 35000
1205 kiran 20 Male 40000
1201 gopal 45 Male 50000
1202 manisha 40 Female 51000
Training
1 1201 csharp
2 1205 c
3 1201 c
4 1202 java
5 1205 java
6 1203 shell
7 1204 hadoop
8 1201 hadoop
Now I want count of males and females who have joined any course.
I tried below query-
hive> select s.sex, count(*) from student join training t on s.id=t.sid group by s.sex;
But this query is giving output as Female 2 Male 4
Though expected outcome should be Female 1 Male 2
Please note this is a sample and short form of data being used.
This looks like your query, but - returns the result you mentioned (1 female, 2 male). If possible, post your own SQL*Plus copy/paste session (take my example) so that we'd see what you exactly did).
SQL> with student (id, name, sex) as
2 (select 1, 'alex', 'm' from dual union
3 select 2, 'rita', 'f' from dual union
4 select 3, 'max', 'm' from dual union
5 select 4, 'steve', 'm' from dual
6 ),
7 training (id, sid, course) as
8 (select 1, 2, 'java' from dual union
9 select 2, 3, 'c' from dual union
10 select 3, 1, 'java' from dual
11 )
12 select s.sex, count(*)
13 from student s join training t on t.sid = s.id
14 group by s.sex;
S COUNT(*)
- ----------
m 2
f 1
I try in MySQL and in Oracle, and this query is OK.
SELECT S.sex, count(*)
FROM student s
INNER JOIN training T on S.id = T.sid
GROUP BY S.sex;
RESULT, female = 1, male = 2
If the only thing you want is a simple count by gender, why not use
select sex, count(*)
from student
group by sex
order by sex
Use exists:
select s.sex, count(*)
from students s
where exists (select 1 from training t where t.sid = s.id);
The problem with join is that it counts each student based on the number of trainings they are in.
Here i had written a code taking your data:-
SELECT
final.ct_sex as sex,count(*) as num
FROM
(SELECT tb.sex as ct_sex FROM newschema.mytable AS tb JOIN (SELECT tr.ID,GROUP_CONCAT(tr.skill) as skills FROM newschema.train AS tr GROUP BY tr.ID) AS tp ON tb.ID = tp.ID) as final
group by
final.ct_sex
Not sure why join fails here, Below subquery is giving correct output though.
select sex, count(*) from salary where salary.id in (select sid from training) group by salary.sex;