sql case statement of case results - sql

I want to take letter grades convert to a number average and then convert back to a letter.
The
select
avg(case when grade = 'A' then 4
when grade = 'B' then 3
when grade = 'C' then 2
when grade = 'F' then 1 end)
from student
where id = 'test'
this works perfectly
I want to now convert the average back to a letter.
I tried and it works but I cant help but think there isn't a better easier way to accomplish this
select case(when (select
avg(case when grade = 'A' then 4
when grade = 'B' then 3
when grade = 'C' then 2
when grade = 'F' then 1)
from student where id = 'test') = 4 then 'A'

Use another CASE expression on the first one:
SELECT
CASE WHEN num_avg <= 1.0 THEN 'F'
WHEN num_avg <= 2.0 THEN 'C'
WHEN num_avg <= 3.0 THEN 'B'
ELSE 'A' END AS avg_letter_grade
FROM
(
SELECT AVG(CASE grade WHEN 'A' THEN 4.0
WHEN 'B' THEN 3.0
WHEN 'C' THEN 2.0
WHEN 'F' THEN 1.0 END) AS num_avg
FROM student
WHERE id = 'test'
) t;
The letter grade assignments I used in the outer query are not in agreement with what my understanding of typical grade scales are, but it is in line with your scale, so I chose to use it.

Related

How to convert a single column containing multiple rows into rows

I have a column , says name Student_name and its values lets say, A, B, C, D, E, F and so on..
Now i have to convert this column into row with each alias.
select A.counts from (
select count(b.ATTND_FLAG) as counts , b.ATTND_FLAG as ATTND_FLAG
from hr_emp_notifications a, v_emp_attendance b
where a.emp_id=b.emp_id
and a.emp_id=90327
and b.ATTND_FLAG is not null
group by b.ATTND_FLAG )A
my query showing one column which has multiple values in rows.
i have to convert these values into row.
I would use conditional aggregation:
select sum(case when ea.attnd_flag = 'A' then 1 else 0 end) as num_a,
sum(case when ea.attnd_flag = 'B' then 1 else 0 end) as num_b,
sum(case when ea.attnd_flag = 'C' then 1 else 0 end) as num_c,
sum(case when ea.attnd_flag = 'D' then 1 else 0 end) as num_d,
sum(case when ea.attnd_flag = 'E' then 1 else 0 end) as num_e,
sum(case when ea.attnd_flag = 'F' then 1 else 0 end) as num_f
from v_emp_attendance ea
where ea.emp_id = 90327;
If you want multiple employees, use group byea.emp_id`.
Notice that the join is not needed.
It seems you need a pivot clause here -
SELECT *
FROM (SELECT NAME, ATTND_FLAG
FROM v_emp_attendance)
PIVOT (COUNT(ATTND_FLAG)
FOR NAME IN ('A' AS A, 'B' AS B, 'C' AS C /* AND SO ON */)
)

How can I select data from multiple SQL tables?

I have 2 tables, as described below:
Grades
student id,
exem1,
exam2,
exam3
Names
student id,
names
I want to display the names of students, their average on the 3 exams, and a letter grade. The letter grade is computed as follows:
90+ is an “A”, 80 - <90 will be a “B”, and so on. How should i do it.?
> SELECT n.student_names, ((g.exam1+g.exam2+g.exam3)/3) AS 'AVERAGE_RESULT', (CASE
WHEN ((g.exam1+g.exam2+g.exam3)/3) =90
THEN 'A'
WHEN (((g.exam1+g.exam2+g.exam3)/3) BETWEEN 80 AND 89)
THEN 'B'
WHEN (((g.exam1+g.exam2+g.exam3)/3) BETWEEN 70 AND 79)
THEN 'C'
ELSE 'D') END AS 'Student_grades',
FROM names n, grades g
WHERE n.students_id = g.students_id;
Using BETWEEN to include the ranges
SELECT n.NAME AS "Name", CASE WHEN ((g.exam1+g.exam2+g.exam3)/3) = 90 then 'A'
WHEN ((g.exam1+g.exam2+g.exam3)/3) < 90 then 'B'
ELSE 'C'
END AS "Grade"
FROM NAMES AS n INNER JOIN GRADES AS g
ON g.student_id = n.student_id
Modify the ranges as you want.

combining boolean results from two columns SQL

I have the following example data from two Boolean columns:
ID Male Female
1 1 0
2 0 1
3 0 1
4 1 0
5 0 1
I would like to combine the two columns into a single column containing just 'M' and 'F'. Also, I would preferably like to do it in the SELECT statement I am writing while defining the column.
The result then should be something like:
ID Gender
1 M
2 F
3 F
4 M
5 F
I know I could achieve this with separate update statements like:
UPDATE table_1
SET Gender='M'
FROM table_2 t2
WHERE t2.Male=1
and
UPDATE table_1
SET Gender='F'
FROM table_2 t2
WHERE t2.Female=1
But I was really hoping to achieve the same result while declaring the Gender column?
Does anyone know if this is possible?
Thanks in advance!
You can use a CASE expression.
Query
UPDATE t1
SET t1.Gender = (
CASE WHEN t2.Male = 1 AND t2.Female = 0 THEN 'M'
WHEN t2.Male = 0 AND t2.Female = 1 THEN 'F'
ELSE NULL END
)
FROM Table_1 t1
JOIN Table_2 t2
ON t1.ID = t2.ID;
UPDATE table_1
SET Gender= CASE WHEN Male = 1 THEN 'M'
WHEN Female = 1 THEN 'F'
ELSE 'Other' // optional
END;
Of course im trying to be open mind and guess you allow Male = 0 and Female = 0
otherwise you can simplify with IIF
UPDATE table_1
SET Gender = IIF ( Male = 1, 'M', 'F' );
Here is how to do it with a SELECT statement:
SELECT ID,
CASE WHEN Male = 1 THEN 'M'
ELSE 'F' END AS gender
FROM My_Table
How about select if(Male = 1, 'M', 'F') as gender?

Select count of unique values that might appear in different columns

I am trying to get a count on values that might appear in 3 different columns but only require the count of unique values. Microsoft SQL.
Eg. value X might appear in column A, B, or C or all 3 but need to make sure I only get a unique count of value X no matter what columns it comes under.
Thanks!
If you want to count each individual occurrence of X in any column A, B, or C, then the following should work:
SELECT
SUM(CASE WHEN A = 'X' THEN 1 ELSE 0 END) +
SUM(CASE WHEN B = 'X' THEN 1 ELSE 0 END) +
SUM(CASE WHEN C = 'X' THEN 1 ELSE 0 END)
FROM yourTable
Is this what you are looking for? This will Count only 1 occurrence per row regardless of how many columns it is found in.
SELECT
ID
,SUM(CASE WHEN ColA = 'X' OR ColB = 'X' OR ColC = 'X' THEN 1 ELSE 0 END) AS ValueCount
FROM
TABLENAME
GROUP BY
ID
I guess I should show it without the group by too because you don't specify a grouping.
SELECT
,SUM(CASE WHEN ColA = 'X' OR ColB = 'X' OR ColC = 'X' THEN 1 ELSE 0 END) AS ValueCount
FROM
TABLENAME

SQL using if statement in stored procedure to update a table

I have a table Students with two fields, StudentName and Grade.
I am trying to write a stored procedure to update the Grade. If the student has an A, I want to change it to B. If they have a B, I want to change it to A. If they have anything else I want to leave it alone. Here is my best attempt
create procedure sp_changegrades
if Grade = 'A' update Students set Grade = 'B'
else if Grade = 'B' update Students set Grade = 'A'
just use CASE
UPDATE Students
SET Grade =
(
CASE WHEN Grade = 'A' THEN 'B'
WHEN Grade = 'B' THEN 'A'
ELSE Grade -- "If they have anything else I want to leave it alone."
END
)
or
UPDATE Students
SET Grade =
(
CASE WHEN Grade = 'A'
THEN 'B'
ELSE 'A'
END
)
WHERE Grade IN ('A','B')
You can utilize a Case statement, and add a where clause so you only update the relavant rows.
UPDATE Students
SET Grade =
(
CASE WHEN Grade = 'A' THEN 'B'
WHEN Grade = 'B' THEN 'A'
ELSE Grade -- "Included for Completeness, should never be utilized."
END
)
WHERE Grade in ('A','B')
you can write smth like this. In this solution you define rules of updating in join part and then updating.
create procedure sp_changegrades
as
begin
update Students set
Grade = G.Grade_New
from Students as S
inner join (values
('A', 'B'),
('B', 'A')
) as G(Grade_Old, Grade_New) on G.Grade_Old = S.Grade
end
or you can use case
create procedure sp_changegrades
as
begin
update Students set
Grade =
case Grade
when 'A' then 'B'
when 'B' then 'A'
else Grade
end
end