multiple query in one query where - sql

I wrote this query for finding the highest score from 2 tables (Selected Item: StudentId and Score), and now I want to select some other data: (StudentName, StudentImage, ...) from other tables that must filter items using StudentId
my query returns:
StudentId HighScoreUser
-1 250
-2 100
-3 90
-4 80
-5 40
For showing data in a grid, I need the Student Name, ... so I must use StudentId to find the info for the specific user:
CREATE PROCEDURE SelectTopYear
AS
SELECT TOP 5 StudentId, ISNULL(SUM(Score),0) As HighScoreUser
FROM (SELECT StudentId, Score FROM tbl_ActPoint
UNION ALL
SELECT StudentId, Score FROM tbl_EvaPoint
) as T
GROUP BY StudentId ORDER BY HighScoreUser DESC
RETURN 0

You can use a CTE (or subquery) and JOIN:
WITH s as (
SELECT TOP 5 StudentId, ISNULL(SUM(Score),0) As HighScoreUser
FROM (SELECT StudentId, Score FROM tbl_ActPoint
UNION ALL
SELECT StudentId, Score FROM tbl_EvaPoint
) s
GROUP BY StudentId
ORDER BY HighScoreUser DESC
)
SELECT . . .
FROM s JOIN
othertable ot
ON s.StudentId = ot.StudentId;
Fill in the appropriate column names and table names.

Related

How to count a temporary variable in SQLite?

I am working on a personal analytics project and I need to filter a SQL table. My SQL knowledge is very basic and moreover, I know that in Oracle but in this case I have to use SQLite and it seems to be quite different.
For example, suppose the table is
student physics chemistry maths history english
Brian 78 62 100 40 50
Bill 80 70 95 50 60
Brian 80 40 90 95 60
The table has repetition.
I asked a question earlier today, using the same example above, which would let me rank the subjects for each student.
How to RANK multiple columns of an entire table?
What I want to do now is find out which students had Maths in the top 3 among all subjects and group the table for each student. So the goal is to find out how many times did Brian have Maths in Top 3 of his scores.
IT WeiHan's answer to the previous question (https://www.db-fiddle.com/f/bjui5W1VWmHXcqKAhK5iBD/0 ) worked perfectly and displayed the rank of the subjects for each row. I used their answer and tried to modify it for this purpose.
with cte as (
select student,'physics' as class,physics as score from Table1 union all
select student,'chemistry' as class,chemistry as score from Table1 union all
select student,'maths' as class,maths as score from Table1 union all
select student,'history' as class,history as score from Table1 union all
select student,'english' as class,english as score from Table1
)
SELECT name,class,score,rnk,
(CASE
WHEN class = "maths" AND rnk <=3 THEN 1
ELSE 0
END) as maths_rank
FROM
(select student,class,score,RANK() OVER (partition by student order by score desc) rnk
from cte)
which gives a table like
name class score rnk maths_rank
Brian maths 100 1 1
I want to be able to count the maths_rank values or sum it (as it contains 1 or 0 values) and group the table on student name. I tried to count the maths_rank variable but that didn't work and resulted in errors. Please help me out with a solution.
If I understand correctly, you are on the right path. I think you just need a where clause:
with cte as (
select student,'physics' as class,physics as score from Table1 union all
select student,'chemistry' as class,chemistry as score from Table1 union all
select student,'maths' as class,maths as score from Table1 union all
select student,'history' as class,history as score from Table1 union all
select student,'english' as class,english as score from Table1
)
select t.*
from (select t.*,
rank() over (partition by student order by score desc) as subject_rank
from cte t
) t
where class = 'maths' and subject_rank <= 3;
Edit:
If you want the number of times maths was in the top 3, then:
select student, sum(case when class = 'maths' and subject_rank <= 3 then 1 else 0 end) as maths_top3
from (select t.*,
rank() over (partition by student order by score desc) as subject_rank
from cte t
) t
group by student;

How to get the largest value of a column in table?

I have the following table:
fileId, studentId,
Given a particular studentId, how can I get the largest fileId that is in the table ?
I saw this other query :
SELECT row
FROM table
WHERE id=(
SELECT max(id) FROM table
)
This would give the row where id is the largest. But what about the largest id for a given student id ? Is it better to match the student in the inner query or outer query ?
if you need the whole row:
select * from table where studentId = your_known_id order by fileId desc limit 1
This seems simplest:
SELECT studentId, MAX(ID)
FROM TableA
GROUP BY studentId
OR With filtering options:
WITH CTE AS
(
SELECT studentId, MAX(ID)
FROM TableA
GROUP BY studentId
)
SELECT * FROM CTE WHERE studentId ...
Try this:
SELECT *
FROM (
SELECT
id,
ROW_NUMBER () OVER (PARTITION BY studentId ORDER BY id desc) rnk
FROM table) a
WHERE a.rnk = 1;
... what about the largest id for a given student id
SELECT MAX(fileId)
FROM table
WHERE studentId = 123
Where 123 is the student if you want to filter on.
say there are three rows with studentId =3, but with fileId's = {4,5,6}, how do i get the row {fileId,studentId} = {6,3}
SELECT MAX(fileId), studentId
FROM table
WHERE studentId = 3
GROUP BY studentId
I think this code works as well
SELECT max(field) from table_name where studenId = <someID>

Select by greatest sum, but without the sum in the result

I need to select the top score of all combined attempts by a player and I need to use a WITH clause.
create table scorecard(
id integer primary key,
player_name varchar(20));
create table scores(
id integer references scorecard,
attempt integer,
score numeric
primary key(id, attempt));
Sample Data for scorecard:
id player_name
1 Bob
2 Steve
3 Joe
4 Rob
Sample data for scores:
id attempt score
1 1 50
1 2 45
2 1 10
2 2 20
3 1 40
3 2 35
4 1 0
4 2 95
The results would simply look like this:
player_name
Bob
Rob
But would only be Bob if Rob had scored less than 95 total. I've gotten so far as to have the name and the total scores that they got in two columns using this:
select scorecard.player_name, sum(scores.score)
from scorecard
left join scores
on scorecard.id= scores.id
group by scorecard.name
order by sum(scores.score) desc;
But how do I just get the names of the highest score (or scores if tied).
And remember, it should be using a WITH clause.
Who ever told you to "use a WITH clause" was missing a more efficient solution. To just get the (possibly multiple) winners:
SELECT c.player_name
FROM scorecard c
JOIN (
SELECT id, rank() OVER (ORDER BY sum(score) DESC) AS rnk
FROM scores
GROUP BY 1
) s USING (id)
WHERE s.rnk = 1;
A plain subquery is typically faster than a CTE. If you must use a WITH clause:
WITH top_score AS (
SELECT id, rank() OVER (ORDER BY sum(score) DESC) AS rnk
FROM scores
GROUP BY 1
)
SELECT c.player_name
FROM scorecard c
JOIN top_score s USING (id)
WHERE s.rnk = 1;
SQL Fiddle.
You could add a final ORDER BY c.player_name to get a stable sort order, but that's not requested.
The key feature of the query is that you can run a window function like rank() over the result of an aggregate function. Related:
Postgres window function and group by exception
Get the distinct sum of a joined table column
Can try something like follows.
With (SELECT id, sum(score) as sum_scores
FROM scores
group by id) as sumScoresTable,
With (SELECT max(score) as max_scores
FROM scores
group by id) as maxScoresTable
select player_name
FROM scorecard
WHERE scorecard.id in (SELECT sumScoresTable.id
from sumScoresTable
where sumScoresTable.score = (select maxScoresTable.score from maxScoresTable)
Try this code:
WITH CTE AS (
SELECT ID, RANK() OVER(ORDER BY SumScore DESC) As R
FROM (
SELECT ID, SUM(score) AS SumScore
FROM scores
GROUP BY ID )
)
SELECT player_name
FROM scorecard
WHERE ID IN (SELECT ID FROM CTE WHERE R = 1)

How to get the 2nd highest from a table where it need to be added first in sql server in a single query?

I was asked this question in an interview, this the table
Roll | Sub | Marks
1 A 20
1 B 21
2 A 15
2 B 19
3 A 21
3 B 22
now i have to find the roll and marks 2nd highest marks obtained by the student
so i answered this :
declare #trytable table
(
roll int,
total int
)
insert #trytable
select Roll, SUM(Marks)
from Student
group by Roll
Select *
from #trytable t
where t.total in (select MAX(total) from #trytable where total not in ( select
MAX(total) from #trytable))
which is giving the correct answer but the interviewer wanted this to be done in single query
by not using the table variable
the result should be
Roll | Total Marks
1 41
so how can i do that ... please let me know
Below query gives the roll numbers who obtained 2nd highest marks summing the two subject marks.
SELECT TOP 1 Roll, Marks
FROM
(
SELECT DISTINCT TOP 2 Roll,
SUM(Marks) over (Partition by Roll) Marks
FROM
YourTable
ORDER BY marks DESC
) temp
ORDER BY Marks
OR
SELECT
DISTINCT Roll,
Marks,
SRANK
FROM
(
SELECT
Roll,
Marks,
DENSE_RANK() OVER( ORDER BY Marks DESC) AS SRANK
FROM
(
SELECT
Roll,
SUM(Marks) over (Partition by Roll) Marks
FROM YourTable
)x
)x
WHERE SRANK=2
If I understand you correctly, you just want to get the total score for the second highest student, and student is identified by roll? If so:
select roll, sum(Marks) from Student group by roll order by total limit 1,1;
Not 100% sure about the 1,1 - what you are saying is, I only want 1 row, and not the first.
It can also be done through simple query:
select Marks from trytable where N = (select count(distinct Marks) from trytable b where a.Marks <= b.Marks)
where N = any value
Or
SELECT Roll,Marks
FROM tableName WHERE Marks =
(SELECT MIN(Marks ) FROM
(SELECT TOP (2) Marks
FROM tableName
ORDER BY Marks DESC) )
You can use analytic functions like RowNumber()
select * from
(Select t.*, RowNumber() over (order by Total desc) as rownum from trytable )
where rownum = 2

SQL query to return only 1 record per group ID

I'm looking for a way to handle the following scenario. I have a database table that I need to return only one record for each "group id" that is contained within the table, furthermore the record that is selected within each group should be the oldest person in the household.
ID Group ID Name Age
1 134 John Bowers 37
2 134 Kerri Bowers 33
3 135 John Bowers 44
4 135 Shannon Bowers 42
So in the sample data provided above I would need ID 1 and 3 returned, as they are the oldest people within each group id.
This is being queried against a SQL Server 2005 database.
SELECT t.*
FROM (
SELECT DISTINCT groupid
FROM mytable
) mo
CROSS APPLY
(
SELECT TOP 1 *
FROM mytable mi
WHERE mi.groupid = mo.groupid
ORDER BY
age DESC
) t
or this:
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY groupid ORDER BY age DESC) rn
FROM mytable
) x
WHERE x.rn = 1
This will return at most one record per group even in case of ties.
See this article in my blog for performance comparisons of both methods:
SQL Server: Selecting records holding group-wise maximum
Use:
SELECT DISTINCT
t.groupid,
t.name
FROM TABLE t
JOIN (SELECT t.groupid,
MAX(t.age) 'max_age'
FROM TABLE t
GROUP BY t.groupid) x ON x.groupid = t.groupid
AND x.max_age = t.age
So what if there's 2+ people with the same age for a group? It'd be better to store the birthdate rather than age - you can always calculate the age for presentation.
Try this (assuming Group is synonym for Household)
Select * From Table t
Where Age = (Select Max(Age)
From Table
Where GroupId = t.GroupId)
If there are two or more "oldest" people in some household (They all are the same age and there is noone else older), then this will return all of them, not just one at random.
If this is an issue, then you need to add another subquery to return an arbitrary key value for one person in that set.
Select * From Table t
Where Id =
(Select Max(Id) Fom Table
Where GroupId = t.GroupId
And Age =
(Select(Max(Age) From Table
Where GroupId = t.GroupId))
SELECT GroupID, Name, Age
FROM table
INNER JOIN
(
SELECT GroupID, MAX(Age) AS OLDEST
FROM table
) AS OLDESTPEOPLE
ON
table.GroupID = OLDESTPEOPLE.GroupID
AND
table.Age = OLDESTPEOPLE.OLDEST
SELECT GroupID, Name, Age
FROM table
INNER JOIN
(
SELECT GroupID, MAX(Age) AS OLDEST
FROM table
**GROUP BY GroupID**
) AS OLDESTPEOPLE
ON
table.GroupID = OLDESTPEOPLE.GroupID
AND
table.Age = OLDESTPEOPLE.OLDEST