I'm trying to solve the "Gradebook Challenge" from KhanAcademy but not in the platform but in SQL Management Studio. And I haven't obtain the same result as on the platform.
This is my code and the error that appears when I try to run it in SQL Management Studio. Yes, I've done the research and now I realise that is not posible use the GROUP BY clause with alias column, but I don't know what else do. So please, I really need a hand on this.
SELECT COUNT(*), Grade,
CASE
WHEN Grade > 90 THEN 'A'
WHEN Grade > 80 THEN 'B'
WHEN Grade > 70 THEN 'C'
ELSE 'F'
END AS LetterGrade
FROM StudentsGrades
GROUP BY Grade
Push the query containing the CASE statement into a subquery or Common Table Expression, eg
use tempdb
go
create table StudentsGrades(Id int identity primary key, StudentId int, Grade int);
insert into StudentsGrades(StudentId,Grade)
values (1,90),(2,99),(3,40),(5,88);
with q as
(
SELECT *,
CASE
WHEN Grade > 90 THEN 'A'
WHEN Grade > 80 THEN 'B'
WHEN Grade > 70 THEN 'C'
ELSE 'F'
END AS LetterGrade
FROM StudentsGrades
)
SELECT LetterGrade, Count(*) CountOfGrade
from q
group by LetterGrade
outputs
LetterGrade CountOfGrade
----------- ------------
A 1
B 2
F 1
(3 rows affected)
Just another option is CROSS APPLY. It allows you to stack calculations and reference the alias.
Example
Select LetterGrade
,CountofGrade = count(*)
From StudentsGrades A
Cross Apply ( values ( CASE WHEN Grade > 90 THEN 'A'
WHEN Grade > 80 THEN 'B'
WHEN Grade > 70 THEN 'C'
ELSE 'F'
END
) )B(LetterGrade)
Group By LetterGrade
Results
LetterGrade CountofGrade
A 1
B 2
F 1
Related
I have a SQL query that returns to me a list of Analysts with amount of claims they've filed and the amount. I know how many Analyst there are for a specific client (6). The problem I'm having is when I run the query, only 4 pop up. If i comment out the WHERE clause (which gives me back each Analysts specific amount), I get all the Analyst, but their amounts are all the same. How do I get back the missing Analysts? I don't care if they return 0... as a matter of fact, that's what i'm trying to figure out along with the count and sums. All help is greatly appreciated. Here's my code:
SELECT
a.auditorID,
fName,
COUNT(DISTINCT case when claims.dateon >='20200726' AND claims.dateon <= '20200909' AND entries.errorCode NOT IN('DP','RB','DN','WP','WA','CE','RC','SI','CI','PE','OV') then claims.rID end) as rTotal1,
SUM(case when claims.dateon >= '20200726' AND claims.dateon <= '20200909' AND entries.errorCode NOT IN('DP','RB','DN','WP','WA','CE','RC','SI','CI','PE','OV') then entries.refundDue else 0.0 end) as rate1,
COUNT(DISTINCT case when claims.dateon >='20200726' AND claims.dateon <= '20200909' AND entries.errorCode IN('DP','RB','DN','WP','WA','CE','RC','SI','CI','PE','OV') then claims.rID end) as pTotal1,
SUM(case when claims.dateon >= '20200726' AND claims.dateon <= '20200909' AND entries.errorCode IN('DP','RB','DN','WP','WA','CE','RC','SI','CI','PE','OV') then entries.refundDue else 0.0 end) as payment1
FROM auditors a
INNER JOIN
(
SELECT auditorID, assignments.clientID FROM assignments INNER JOIN assignmentCarriers ac ON ac.acID=Assignments.acID WHERE isAssignment='True' GROUP BY auditorID, assignments.clientID
) tAssignments ON tAssignments.auditorID=a.auditorID
INNER JOIN
(
SELECT clientID, code FROM clients WHERE code='ABBL'
) tClients ON tClients.clientID=tAssignments.clientID
INNER JOIN claims ON claims.client=tClients.code
INNER JOIN entries ON claims.rID = entries.rid
WHERE claims.auditorID=a.auditorID
GROUP BY a.auditorID, fName
ORDER BY fName
Here's what I'm getting when I run the code without the SUM or COUNT...
98 User 1
99 User 2
21 User 3
61 User 4
103 User 5
172 User 6
Here's with the constraints
98 User 1 17 147346.3000 1 9451.1600
21 User 2 0 0.0000 21 182958.5100
61 User 3 5 36970.0000 81 353592.8000
103 User 4 534 319697.5774 58 234350.7900
I have this table in sql server i wanted to create a calculated field base on the result of the column that i have, i want the result to display this.
column names are
Key,Homework,Quiz,Exam,Result,Grade
Result=>90 "A+,"Result=>80 "A",Result=>70 "B+",Result=>60 "B"
CREATE TABLE dbo.T
(
Val INT,
Chr AS (
CASE
WHEN Val <= 59 THEN ''
WHEN Val BETWEEN 60 AND 69 THEN 'B'
WHEN Val BETWEEN 70 AND 79 THEN 'B+'
WHEN Val BETWEEN 80 AND 89 THEN 'A'
WHEN Val >= 90 THEN 'A+'
END
)
)
INSERT INTO dbo.T(Val) VALUES (100),(80),(75)
SELECT * FROM dbo.T
DROP TABLE IF EXISTS dbo.T
You need to use concept of derived table like below. I am using result column to derive a new column grade using case statements.
create table #tbl(col1 varchar(2), col2 varchar(2), col3 varchar(2), result int)
insert into #tbl(col1,col2,col3,result) values
('A','A','A',10),
('A','A','B',62),
('A','A','C',83),
('A','A','D',94)
SELECT a.col1, a.col2, a.col3, a.result,
case when a.result < 60 then ''
when a.result between 60 AND 69 then 'B'
when a.result between 70 AND 79 then 'B+'
when a.result between 80 AND 89 then 'A'
when a.result > 89 then 'A+'
else NULL
end as grade
FROM
(
Select col1, col2, col3, result
from #tbl
) a
drop table #tbl;
As a computed column...
ALTER TABLE MyTable ADD Grade AS
CASE
WHEN Result < 60 THEN ''
WHEN Result < 70 THEN 'B'
WHEN Result < 80 THEN 'B+'
WHEN Result < 90 THEN 'A'
ELSE 'A+'
END
If you have fractions (which I've seen at the British Open University) you need to rely on CASE evaluation order and <
Using BETWEEN (like other answers) will means a score of 69.5 will not be graded correctly
SQL Server Docs reference
A CASE example
Hi All,
I am having marks of student in Different Subjects.
Table #Maths Contain marks in maths of students named as a,b and c.
Similar for #Science and #English.
Now i want output as if student have more than 75 marks in two subject he will be given grade as 'Merit'.If he is having more than 75 in one subject and more than 60 in other then grade will be 'Pass' and if none of subject is having more than 75 and one subject is less than 50 then he will be given grade as 'Fail'?
Please Provide me the solution for the result?
Thanks
SELECT m.id, m.name, m.marks, s.marks, e.marks,
CASE WHEN (m.marks > 75 and s.marks > 75) OR (s.marks > 75 and e.marks > 75) OR (m.marks > 75 and e.marks > 75) THEN 'Pass'
WHEN (m.marks > 75 and (s.marks > 60 OR e.marks > 60)) OR
(s.marks > 75 and (m.marks > 60 OR e.marks > 60)) OR
(e.marks > 75 and (s.marks > 60 OR m.marks > 60)) THEN 'Pass'
WHEN (m.marks < 75 and s.marks < 75 and e.marks < 75 and (m.marks < 50 or e.marks < 50 or s.marks < 50)) THEN 'Fail'
ELSE NULL END as Merit
FROM #maths m
inner join #science s
on m.ID = s.ID
inner join #English e
on m.ID = e.ID
Not very classy but since there are only few columns that needs to be compared, i'd approach it this way
You can try a query like below:
This query is definitely faster than Joins as it reduces the operation set for the case condition
The business logic is neatly encapsulated as part of weights and top query conditions
No Joins and therefore faster. Speed will become apparent when you start increasing student records and subject tables.
Query:
select
id,
name,
case
when sum(weightRank) >=32 then "Merit"
when sum(weightRank) >=20 then "Pass"
when sum(weightRank) <16 and count(ALL weightRank) < count(weightRank)
then "Fail"
else "N/A"
end as grade
from
(
select id,name,'m' as subject,marks from #maths
union all
select id,name,'m' as subject,marks from #science
union all
select id,name,'m' as subject,marks from #english
) allmarks
-- allmarks get all records together, and is faster than joining all tables
-- this is also extensible as subjects and students may increase
-- and not all subjects may have marks for all students, so we will not lose data as in case of joins
join
(values (NULL,0, 50),(1,51, 60),(4,61, 75), (16,76,100)
as I(weightRank,lowNumber, highNumber)
-- here we create a temp dynamic table to weight the marks
on
allmarks.marks between I.lowNumber AND I.HighNumber
group by id,name
I'd like to either add a case statement to return Y/N for the 'All Complete?' column or exclude all rows where 'All complete' = 'Y'.
In order for 'All Complete' to be set to Y, all ID_Status's need to be complete for each customer and each code number. Each customer can have multiple ID's or Code_Number. I'm having trouble understanding CASE logic across multiple columns where values aren't always the same. Thanks for any help.
IDTable:
ID ID_Status Customer Code_Number All Complete?
1 Complete Alex 123 Y
2 Complete Alex 123 Y
3 Complete Brian 321 Y
4 Complete Brian 321 Y
5 Open Brian 425 N
6 Complete Brian 425 N
7 Open Charlie 123 N
8 Complete Charlie 123 N
9 Open Charlie 123 N
10 Complete Donald 555 N
11 Complete Donald 555 N
12 Testing Donald 555 N
13 Complete Eric 620 Y
Assuming SQL Server 2008+:
WITH CTE AS
(
SELECT *,
COUNT(*) OVER(PARTITION BY Customer, Code_Number) Total,
SUM(CASE WHEN Id_Status = 'Complete' THEN 1 ELSE 0 END) OVER(PARTITION BY Customer, Code_Number) Completed
FROM dbo.YourTable
)
SELECT ID,
ID_Status,
Customer,
Code_Number,
CASE WHEN Total = Completed THEN 'Y' ELSE 'N' END [All Complete]
FROM CTE;
Select *
, CASE WHEN EXISTS
(SELECT 1 FROM TableName t1
Where t1.Customer = t2.Customer
AND t1.Code_Number = t2.Code_Number
AND t1.ID_Status <> 'Complete'
)
THEN 'N' ELSE 'Y' END AS [All Complete?]
from TableName t2
How can I get a count of employees whose name starts with A or B? The result should look like the table bellow.
===========
A | B |
===========
5 | 8 |
-----------
You can always use CASE
SELECT
SUM(case when first_name like 'A%' then 1 else 0 end) 'A' ,
SUM(case when first_name like 'B%' then 1 else 0 end) 'B'
FROM tableName
Query basically means add 1 to column A for every first_name that starts with A.
Based on my understanding.
Below Query will return two columns 1 :Starting Alphabet, 2: Count.
SELECT LEFT(employees, 1) , Count(LEFT(employees, 1)) FROM
TableName GROUP BY LEFT(employees, 1)