I have two table. One table contains graduation records and the second table contains post graduation records. A candidate must have graduation, but it is not necessarily to have post graduation.
My question is to select the post graduation record if the candidate has post graduation else only graduation.
table 1 graduation_table
rollno | degree | division
--------------------------
001 | B.tech | 1st
002 | B.sc | 1st
003 | BA | 1st
table 2 postgraduation_table
rollno | degree | division
--------------------------
002 | M.sc | 1st
the result must be
rollno | degree | division
--------------------------
001 | B.tech | 1st
002 | M.sc | 1st
003 | BA | 1st
You want all rows from graduation_table which do not have a row in postgraduation_table plus those in postgraduation_table. This can be expressed with a not exists and union query:
select gt.rollno, gt.degree, gt.division
from graduation_table gt
where not exists (select *
from postgraduation_table pg
where pg.rollno = gt.rollno)
union all
select rollno, degree, division
from postgraduation_table
order by rollno;
Online example: http://rextester.com/IFCQR67320
select
rollno,
case when p.degree is null then g.degree else p.degree end as degree,
case when p.division is null then g.division else p.division end as division
from
grad g
left join
post p using (rollno)
Or better as suggested in the comments:
select
rollno,
coalesce (p.degree, g.degree) as degree,
coalesce (p.division, g.division) as division
from
grad g
left join
post p using (rollno)
Take a union of both tables, and introduce a position column, to rank the relative importance of the two tables. The postgraduate table has a pos value of 1, and the graduate table has a value of 2. Then, apply ROW_NUMBER() over this union query and assign a row number to each rollno group of records (presumed to be either one or at most two records). Finally, perform one more outer subquery to retain the most important record, postgraduate first, graduate second.
SELECT rollno, degree, division
FROM
(
SELECT
rollno, degree, division,
ROW_NUMBER() OVER (PARTITION BY rollno ORDER BY pos) rn
FROM
(
SELECT p.*, 1 AS pos p FROM postgraduation_table
UNION ALL
SELECT p.*, 2 FROM graduation_table p
) t
) t
WHERE t.rn = 1;
This should make your needs :
SELECT dg.rollno, CASE WHEN pg IS NOT NULL THEN pg.degree ELSE gd.degree END AS degree, dg.division
FROM graduation_table AS dg
LEFT OUTER JOIN postgraduation_table AS pg USING (rollno)
GROUP BY dg.rollno, dg.division;
Hope this help.
Related
I'm really new to this and this particular question has been bugging me for days. I do know there are similar questions to this but I kept wondering how it would be done in subqueries.
SALARY TABLE
[Emp_ID] [SalaryPM]
001 | 10,500
002 | 50,000
003 | 8,000
004 | 10,000
DEPT TABLE
[Emp_ID] [Dept_ID]
001 | A
002 | B
003 | C
004 | C
I want it to look like this
[Emp_ID] [Dept_ID] [SalaryPM]
001 | A | 10,000
002 | B | 50,000
004 | C | 10,000
What I have tried so far, but it only gives the highest salary of the employee##
SELECT * FROM DEPT
WHERE EMP_ID IN
(SELECT Emp_ID
FROM SALARY
WHERE SalaryPM = (SELECT MAX(SalaryPM)
FROM SALARY));
Would this qualify as a subquery solution?
select *
from (
select s.*, e.deptid,
rank() over(partition by e.dept order by s.salaries desc) rn
from employees e
inner join salaries s on s.id = e.id
) rn
where rn = 1
Note: your does not look good. The data you are showing suggests a 1-1 relationship between the two tables (wich I called employees and salaries): if so, both tables should be combined in a single table.
I would be good to know what do you mean by "using subqueries" ;)
here's another solution using subquery in the SELECT clause
SELECT
d.id,
d.deptid,
(
SELECT
MAX(s.salary)
FROM
my_salaries s
WHERE
s.id = d.id
) max_salary
FROM
my_departments d;
here's solution without joining tables (IMHO not joining tables is just overcomplicating things). Why 'not using join' is so important for you?
SELECT
sub.id,
MAX(sub.deptid),
MAX(sub.salary)
FROM
(
SELECT
d.id,
d.deptid,
NULL salary
FROM
my_departments d
UNION ALL
SELECT
s.id,
NULL deptid,
s.salary
FROM
my_salaries s
) sub
GROUP BY
sub.id
ORDER BY
sub.id;
I have one database and time to time i change some part of query as per requirement.
i want to keep record of results of both before and after result of these queries in one table and want to show queries which generate difference.
For Example,
Consider following table
emp_id country salary
---------------------
1 usa 1000
2 uk 2500
3 uk 1200
4 usa 3500
5 usa 4000
6 uk 1100
Now, my before query is :
Before Query:
select count(emp_id) as count,country from table where salary>2000 group by country;
Before Result:
count country
2 usa
1 uk
After Query:
select count(emp_id) as count,country from table where salary<2000 group by country;
After Query Result:
count country
2 uk
1 usa
My Final Result or Table I want is:
column 1 | column 2 | column 3 | column 4 |
2 usa 2 uk
1 uk 1 usa
...... but if query results are same than it shouldn't show in this table.
Thanks in advance.
I believe that you can use the same approach as here.
select t1.*, t2.* -- if you need specific columns without rn than you have to list them here
from
(
select t.*, row_number() over (order by count) rn
from
(
-- query #1
select count(emp_id) as count,country from table where salary>2000 group by country;
) t
) t1
full join
(
select t.*, row_number() over (order by count) rn
from
(
-- query #2
select count(emp_id) as count,country from table where salary<2000 group by country;
) t
) t2 on t1.rn = t2.rn
I'm making an app that shows people movies to rate, a-la hot-or-not. I'd like to write a query that gets me the number of times a movie has been rated. The table for ratings looks like this:
| id | winner | loser |
| 1 | 1 | 2 |
| 2 | 2 | 3 |
| 3 | 1 | 3 |
I can get the number of times a movie has "won" by running a query like this:
SELECT winner, count(winner) AS number_of_wins
FROM movie_results
GROUP BY winner
ORDER BY number_of_wins DESC;
But I'd like to get another query that shows the total number of times a movie was pitched against other movies, i.e. the number of times a movie has appeared to be rated, whether it was rated above or below the other movie. What is the easiest way to achieve this, using only SQL queries?
Here is one method, using union all:
select movie, count(*) as nummatches, sum(win) as numwins
from ((select winner as movie, 1 as win from match_results) union all
(select loser, 0 from match_results)
) wl
group by movie;
You can do a full join between two derived tables where each table contains the number of losses and wins for each player.
select
coalesce(winner,loser) player,
coalesce(number_of_wins,0) number_of_wins,
coalesce(number_of_losses,0) number_of_losses,
coalesce(number_of_wins,0) + coalesce(number_of_losses,0) number_of_matches
from (
select winner, count(*) number_of_wins
from movie_results
group by winner
) winners full join (
select loser, count(*) number_of_losses
from movie_results
group by loser
) losers on losers.loser = winners.winner
http://sqlfiddle.com/#!15/980d6/3
I've tried more or less all combinations of count and distinct (except the correct one :) ) in order to get the example below.
Input: table t1
NAME | FOOD
Mary | Apple
Mary | Banana
Mary | Apple
Mary | Strawberry
John | Cherries
Expected output:
NAME | FOOD
Mary | 3
John | 1
N.B. Mary has Apple in two rows but she has 3 as we have 3 different values in the column.
I only managed to get 4 in FOOD Column for her, but I need 3 :(
select a.name as NAME, a.count(name) as Food
from
(SELECT distinct NAME,Food from table)a
Start with a query which gives you unique combinations of NAME and FOOD:
SELECT DISTINCT t1.NAME, t1.FOOD
FROM t1
Then you can use that as a subquery in another where you can GROUP BY and Count:
SELECT sub.NAME, Count(*) AS [FOOD]
FROM
(
SELECT DISTINCT t1.NAME, t1.FOOD
FROM t1
) AS sub
GROUP BY sub.NAME;
select a.name, sum(a.FoodCount) from(
select distinct name,COUNT(food) as FoodCount from #t1 group by name, food ) as a group by a.name order by 2 desc
How would I be able to get N results for several groups in
an oracle query.
For example, given the following table:
|--------+------------+------------|
| emp_id | name | occupation |
|--------+------------+------------|
| 1 | John Smith | Accountant |
| 2 | Jane Doe | Engineer |
| 3 | Jack Black | Funnyman |
|--------+------------+------------|
There are many more rows with more occupations. I would like to get
three employees (lets say) from each occupation.
Is there a way to do this without using a subquery?
I don't have an oracle instance handy right now so I have not tested this:
select *
from (select emp_id, name, occupation,
rank() over ( partition by occupation order by emp_id) rank
from employee)
where rank <= 3
Here is a link on how rank works: http://www.psoug.org/reference/rank.html
This produces what you want, and it uses no vendor-specific SQL features like TOP N or RANK().
SELECT MAX(e.name) AS name, MAX(e.occupation) AS occupation
FROM emp e
LEFT OUTER JOIN emp e2
ON (e.occupation = e2.occupation AND e.emp_id <= e2.emp_id)
GROUP BY e.emp_id
HAVING COUNT(*) <= 3
ORDER BY occupation;
In this example it gives the three employees with the lowest emp_id values per occupation. You can change the attribute used in the inequality comparison, to make it give the top employees by name, or whatever.
Add RowNum to rank :
select * from
(select emp_id, name, occupation,rank() over ( partition by occupation order by emp_id,RowNum) rank
from employee)
where rank <= 3
tested this in SQL Server (and it uses subquery)
select emp_id, name, occupation
from employees t1
where emp_id IN (select top 3 emp_id from employees t2 where t2.occupation = t1.occupation)
just do an ORDER by in the subquery to suit your needs
I'm not sure this is very efficient, but maybe a starting place?
select *
from people p1
join people p2
on p1.occupation = p2.occupation
join people p3
on p1.occupation = p3.occupation
and p2.occupation = p3.occupation
where p1.emp_id != p2.emp_id
and p1.emp_id != p3.emp_id
This should give you rows that contain 3 distinct employees all in the same occupation. Unfortunately, it will give you ALL combinations of those.
Can anyone pare this down please?