Let's say I have a bases with a table:
-courses (key: name [ofthecourse], other attributes: year in which the course takes place)
I want to complete a query looking for an answer to the question:
On which year of study there is a maximum number of courses?
Normally, the query would be:
SELECT TOP 1 STUDYEAR
FROM COURSES
GROUP BY STUDYEAR
ORDER BY COUNT(CNO) DESC;
But my question is, which query could complete this without using the TOP 1 phrase?
You can use an inner query to get the maximum count. The only difference is though that it can return more than one record if they have the same count.
SELECT STUDYEAR
FROM COURSES
GROUP BY STUDYEAR
HAVING COUNT(CNO) = (SELECT MAX(CNOCount) FROM
(SELECT COUNT(CNO) CNOCount
FROM COURSES
GROUP BY STUDYEAR) X)
Another version with only one inner query:
SELECT STUDYEAR
FROM
(SELECT STUDYEAR, ROW_NUMBER() OVER (ORDER BY COUNT(CNO) DESC) RowNumber
FROM COURSES
GROUP BY STUDYEAR) X
WHERE RowNumber = 1
Related
I have two tables as follows:
I want to find the StudentId, FirstName, StudentLoginInfoId, LoginDate. I am expecting only one entry per student with higher LoginDate.
Expected result:
You could use ROW_NUMBER to number output of the result-set for each partition (here each student) in a subquery and achieve your desired output by applying a condition of the number assigned for each student to be 1 which will equal one row.
select studentid, firstname, studentlogininfoid, logindate
from (
select
s.studentid, s.firstname, sl.studentlogininfoid, sl.logindate,
row_number() over (partition by sl.studentid order by sl.logindate desc) as rn
from student s
inner join studentlogininfoid sl on s.studentid = sl.studentid
) t
where rn = 1
Explaining arguments for row_number:
PARTITION BY specifies what are your groups to enumerate separately (start from 1 for each group)
ORDER BY specifies how should rows be enumerated (based on which order)
If we enumerate rows for each student and sort them from latest date descending, then the first row for each student (the row with rn = 1) will contain highest login date value for that student.
You can use "CROSS APPLY" to find what you want:
SELECT S.StudentId
, S.FirstName
, SLI.StudentLoginInfoId
, SLI.LoginDate
FROM Student S
CROSS APPLY (SELECT TOP 1 * FROM StudentLoginInfo SLI WHERE S.StudentId = SLI.StudentId ORDER BY LoginDate DESC) SLI
I need to perform TREAMMEAN in Access, which does not have this function.
In a table I have many Employees, each has many records.
I need to TRIMMEAN Values for each Employee separately.
Following queries perform TOP 10 percent for all records:
qry_data_TOP10_ASC
qry_data_TOP10_DESC
unionqry_TOP10_ASCandDESC
qry_data_ALL_minus_union_qry
After that, I can use Avg (Average).
But I don't know how to do it for each employee.
Visualization:
Note:
This question is edited to simplify problem.
You don't really give information in your pseudo code about your data fields but using your example that DOES have basic field information I can suggest the following should work as you described
It assumes field1 is your unique record ID - but you make no mention of which fields are keys
SELECT AVG(qry_data.field2) FROM qry_data WHERE qry_data.field1 NOT IN
(SELECT * FROM
(SELECT TOP 10 PERCENT qry_data.field1, qry_data.field2
FROM qry_data
ORDER BY qry_data.field2 ASC)
UNION
(SELECT TOP 10 PERCENT qry_data.field1, qry_data.field2
FROM qry_data
ORDER BY qry_data.field2 DESC)
)
This should give you what you want, the two sub-queries should correlate the TOP 10s (ascending and descending) for every employee. The two NOT INs should then remove those from the Table1 records and then you group the Employees and Average the Scores.
SELECT Table1.Employee, AVG(Table1.Score) AS AvgScore
FROM Table1
WHERE ID NOT IN
(
SELECT TOP 10 ID
FROM Table1 a
WHERE a.Employee = Table1.Employee
ORDER BY Score ASC, Employee, ID
)
AND ID NOT IN
(
SELECT TOP 10 ID
FROM Table1 b
WHERE b.Employee = Table1.Employee
ORDER BY Score DESC, Employee, ID
)
GROUP BY Table1.Employee;
I have a table named grades. A column named Students, Practical, Written. I am trying to figure out the top 5 students by total score on the test. Here are the queries that I have not sure how to join them correctly. I am using oracle 11g.
This get's me the total sums from each student:
SELECT Student, Practical, Written, (Practical+Written) AS SumColumn
FROM Grades;
This gets the top 5 students:
SELECT Student
FROM ( SELECT Student,
, DENSE_RANK() OVER (ORDER BY Score DESC) as Score_dr
FROM Grades )
WHERE Student_dr <= 5
order by Student_dr;
The approach I prefer is data-centric, rather than row-position centric:
SELECT g.Student, g.Practical, g.Written, (g.Practical+g.Written) AS SumColumn
FROM Grades g
LEFT JOIN Grades g2 on g2.Practical+g2.Written > g.Practical+g.Written
GROUP BY g.Student, g.Practical, g.Written, (g.Practical+g.Written) AS SumColumn
HAVING COUNT(*) < 5
ORDER BY g.Practical+g.Written DESC
This works by joining with all students that have greater scores, then using a HAVING clause to filter out those that have less than 5 with a greater score - giving you the top 5.
The left join is needed to return the top scorer(s), which have no other students with greater scores to join to.
Ties are all returned, leading to more than 5 rows in the case of a tie for 5th.
By not using row position logic, which varies from darabase to database, this query is also completely portable.
Note that the ORDER BY is optional.
With Oracle's PLSQL you can do:
SELECT score.Student, Practical, Written, (Practical+Written) as SumColumn
FROM ( SELECT Student, DENSE_RANK() OVER (ORDER BY Score DESC) as Score_dr
FROM VOTES ) as score, students
WHERE score.score_dr <= 5
and score.Student = students.Student
order by score.Score_dr;
You can easily include the projection of the first query in the sub-query of the second.
SELECT Student
, Practical
, Written
, tot_score
FROM (
SELECT Student
, Practical
, Written
, (Practical+Written) AS tot_score
, DENSE_RANK() OVER (ORDER BY (Practical+Written) DESC) as Score_dr
FROM Grades
)
WHERE Student_dr <= 5
order by Student_dr;
One virtue of analytic functions is that we can just use them in any query. This distinguishes them from aggregate functions, where we need to include all non-aggregate columns in the GROUP BY clause (at least with Oracle).
I was told to Find out which occupation has the greatest number of patients with conditionID=MC8
I dk how to do the greatest part.....
Here my code right now
SELECT occupation
FROM Patient
WHERE EXISTS
(SELECT PatientID FROM PatientMedcon
Where conditionID=’MC8’)
GROUP BY occupation
HAVNG count(occupation) = (Select max(occupation)
From Patient
You should approach these types of queries using regular joins and then add additional factors. The following gets the count of patients for each occupation with that condition:
SELECT occupation, COUNT(*)
FROM Patient p JOIN
PatentMedcon pm
ON p.PatientId = pm.PatientId and
pm.conditionId = 'MC8'
GROUP BY occupation
ORDER BY COUNT(*) DESC;
If you want the top row, that depends on the database. It might be select top 1, limit 1 at the end, fetch first 1 rows only at the end, or even something else.
I am trying to find a query that would give me a count of another table in the query. The problem is that I have no idea what to set where in the count part to. As it is now it will just give back a count of all the values in that table.
Select
ID as Num,
(select Count(*) from TASK where ID=ID(Also tried Num)) as Total
from ORDER
The goal is to have a result that reads like
Num Total
_________________
1 13
2 5
3 22
You need table aliases. So I think you want:
Select ID as Num,
(select Count(*) from TASK t where t.ID = o.ID) as Total
from ORDER o;
By the way, ORDER is a terrible name for a table because it is a reserved work in SQL.
You can do it as a sub query or a join (or an OVER statement.)
I think the join is clearest when you are first learning SQL
Select
ID as Num, count(TASK.ID) AS Total
from ORDER
left join TASK ON ORDER.ID=TASK.ID
GROUP BY ORDER.ID