Student Result based on passed and failed remarks using SQL Server - sql-server

I have a table that stores students exam results. In that table I have a nvarchar column REMARKS; if obtained marks are less then passing marks, the system adds Pass/Fail to Remarks in that particular column.
The problem is now I am showing whole result with total marks obtained and also display if a student has passed or failed, based on the a query like
If remarks = 'Fail'
and fail is more than one subject in that exam than display Fail else Pass. I searched and tried a lot but no luck. can anyone please tell me how to get it done?
Thanks!
UPDATE:
Tried so far:
SELECT
StudentName,
Year,
ExamType,
SUM(TotalMarks) AS TotalMarks,
SUM(ObtainedMarks) AS ObtMarks
FROM
[dbo].[Exam]
WHERE
ExamType = #Type AND Year = #Year
Looking for a query something like:
CASE WHEN [Remarks] = 'Fail' and having count > 1 THEN 'Fail' ELSE 'Pass' End as 'Status'

The following query returns 'fail' is there is more than one fail in the ExamType and year for a student
SELECT StudentName
,#Year
,#Type
,Sum(TotalMarks) as TotalMarks
,Sum(ObtainedMarks) as ObtMarks
,CASE WHEN Count(CASE WHEN [Remarks] = 'Fail' THEN 1 END) > 1 THEN 'Fail' ELSE 'Pass' End as 'Status'
FROM [dbo].[Exam]
Where ExamType = #Type And Year = #Year
Group by StudentName

Related

How do I select records into a single row?

I've tried writing my sql query to select multiple records on to one row but it isn't working the way I expected it to
Currently my table looks something like this
person id
fruit
1
apple
1
orange
1
banana
2
apple
2
orange
3
apple
I've tried using CASE and GROUP BY but it just gave extra records and didn't display the way I wanted it to and is displaying like this
SELECT DISTINCT
F.MEMBER
,F.GIVEN_NAMES
,F.SURNAME
--VALUES NEEDED
,CASE WHEN F.VALUE_NEEDED = 'Postal Address' THEN 'Yes' ELSE '' END POSTAL_ADDRESS
,CASE WHEN F.VALUE_NEEDED = 'Birthday' THEN 'Yes' ELSE '' END BIRTHDAY
,CASE WHEN F.VALUE_NEEDED = 'Email Address' THEN 'Yes' ELSE '' END EMAIL_ADDRESS
,CASE WHEN F.VALUE_NEEDED = 'First Name' THEN 'Yes' ELSE '' END FIRST_NAME
,CASE WHEN F.VALUE_NEEDED = 'Surname' THEN 'Yes' ELSE '' END SURNAME
,CASE WHEN F.VALUE_NEEDED = 'Title and Gender' THEN 'Yes' ELSE '' END 'TITLE|GENDER'
,CASE WHEN F.VALUE_NEEDED = 'Mobile' THEN 'Yes' ELSE '' END MOBILE
,CASE WHEN F.VALUE_NEEDED = 'Beneficiary' THEN 'Yes' ELSE '' END BENEFICIARY
FROM #FINAL F
GROUP BY F.MEMBER,F.GIVEN_NAMES
,F.SURNAME,VALUE_NEEDED
ORDER BY F.MEMBER
person id
apple
orange
banana
1
yes
1
yes
1
yes
How do I write the query so it looks more like this?
person id
apple
orange
banana
1
yes
yes
yes
2
yes
yes
3
yes
You are almost there, just needed to add the max and group by to aggregate it . This used to be a typical interview question back then.
Some thing like this if I understood correctly
with t as
(
select 1 as person_id, 'apple' fruit
union
select 1 ,'orange'
union
select 1 ,'banana'
union
select 2 ,'apple'
union
select 2 ,'orange'
union
select 3 ,'apple'
)
, b as
(
select
person_id,
case when fruit= 'apple' then 'yes' else null end 'apple',
case when fruit= 'orange' then 'yes' else null end 'orange',
case when fruit= 'banana' then 'yes' else null end 'banana'
from t
)
select
person_id,
max(apple) apple,
max(orange) orange,
max(banana) banana
from b
group by 1;
person_id
apple
orange
banana
1
yes
yes
yes
2
yes
yes
NULL
3
yes
NULL
NULL
You have tagged the tool that you are using (SQL Server Management Studio) which can be used with different DBMS. As Microsoft's SQL Server is the most typical used in this tool, I assume your are using that.
First let's look at your table. It seems a bit weird. It seems to be a kind of key-value table (aka EAV). Each row tells us for an attribute whether it is needed for a person. Now how to identify a person in the table? Is the column member a unique person ID? Probably not, because then, what would be given_names and surname be for in that table, that can change with every entry. Why would the same person with the ID 1234 be called John Smith when the value_needed is 'Birthday', but be called 'Anne Miller' when value_needed is 'Mobile'? That wouldn't make much sense. So maybe member is just a flag, whether a person is a member or not, and a person is uniquely identified by their given_names and surname. But then again, why would the same person John Smith be a member when value_needed is 'Birthday', but not a member when value_needed is 'Mobile'? So something is amiss here. It seems your table is not normalized. Better have one person table and one table for the attributes.
That being said, GROUP BY ___ means "I want one result row per ___". You group by the person and their value_needed. But you don't want one result row per person and value_needed. You want one resut row per person. Hence, group by person.
Then you SELECT DISTINCT .... This means you want to remove duplicate rows. But look at the rows you are selecting. There are no duplicates. If you use GROUP BY, you can be 99.99% sure you don't need DISTINCT. (There do exist rare situations where you voluntarily group by columns, don't select all of them and then apply DISTINCT, but these are so rare that you probably won't ever use them at all.)
Now to the task: You want to get from rows to columns. This is called pivot and can be achieved with the PIVOT keyword, but it is more common to use conditional aggregation. "Conditional aggregation" means that you aggregate your data (per person) and then apply a condition. In standard SQL:
SELECT MIN('YES') FILTER (WHERE f.value_needed = 'Postal Address')
You can use MIN or MAX here, and it is only required for syntax reasons (the FILTER clause must refer to some aggregation function.
In SQL Server there is no FILTER clause, so you use a CASE expression instead:
SELECT MIN(CASE WHEN f.value_needed = 'Postal Address' THEN 'YES' END)
If you want the empty string '' instead of NULL, apply COALESCE:
SELECT COALESCE(MIN(CASE WHEN f.value_needed = 'Postal Address' THEN 'YES' END), '')
Columns aliases containing special characters like | require quoting. But not single quotes, as these denote string literals. In standard SQL use double quotes, in SQL Server use brackets. But better, just avoid them alltogether, by avoiding special characters in names.
The complete query:
SELECT
person_id,
MIN(CASE WHEN value_needed = 'Postal Address' THEN 'yes' end) AS postal_address,
MIN(CASE WHEN value_needed = 'Birthday' THEN 'Yes' end) AS birthday,
MIN(CASE WHEN value_needed = 'Email' THEN 'Yes' END) AS email_address,
MIN(CASE WHEN value_needed = 'First Name' THEN 'Yes' END) AS first_name,
MIN(CASE WHEN value_needed = 'Surname' THEN 'Yes' END) AS surname,
MIN(CASE WHEN value_needed = 'Title and Gender' THEN 'Yes' END) AS title_gender,
MIN(CASE WHEN value_needed = 'Mobile' THEN 'Yes' END) AS mobile,
MIN(CASE WHEN value_needed = 'Beneficiary' THEN 'Yes' END) AS beneficiary
FROM #FINAL
GROUP BY person_id
ORDER BY person_id;

Set all column values based on condition existing in one row using Snowflake

Working on a view in Snowflake and based certain criteria I want to set the Pass/Fail column for all rows to "Pass" if a certain output is reached. Example (below)for a give Item number/ Plant combination, where the condition is met for one row, I would like to set all rows to "Pass"
Here is my case statement as is: I'm Having trouble getting this scenario to "Pass" for all rows
case
when
((case
when 'PIRStatus' is null
then 'PIR-Missing'
else 'PIR-Exists'
end)='PIR-Exists'
and "FixedVendor" = 'X'
and (case
when "SLStatus" = 'SL-Exists'
then 1
else 2
end) = 1)
then 'Pass'
else 'Fail'
end as "Pass/Fail"
PIRStatus Vendor BlockedVendor FixedVendor SLStatus Pass/Fail
PIR-Exists 12547 X SL-Exists Pass
PIR-Exists 85996 SL-Missing Fail
PIR-Exists 54788 SL-Missing Fail
This is based on a given Item/ Plant combination, as long as any row says pass then I want the other rows to Pass as well
You probably want to use a correlated subquery, which I find is best written with a CTE like this:
WITH CTE_CONDITION AS (
SELECT
id,
case when (
(
case when 'PIRStatus' is null then 'PIR-Missing' else 'PIR-Exists' end
)= 'PIR-Exists'
and "FixedVendor" = 'X'
and (
case when "SLStatus" = 'SL-Exists' then 1 else 2 end
) = 1
) then 'Pass' else 'Fail' end as "Pass/Fail"
FROM
table
)
SELECT
* ,
CASE WHEN EXISTS (SELECT 1 FROM CTE_CONDITION WHERE "Pass/Fail" = 'Pass' AND table.id = CTE_CONDITION.id)
THEN 'This ID Passes At Least Somewhere'
ELSE 'This ID never passes'
END as DOES_THIS_EVER_PASS
FROM table
The thing to remember using EXISTS is that the SELECT portion doesn't really matter (thus, SELECT 1) but it is the WHERE clause that connects the table itself to CTE_CONDITION.
You might even clean this up by creating CTE_PASS and CTE_FAIL and putting conditions in the WHERE clauses, to compartmentalize the logic and avoid that messy CASE statement.
Thus, you could accomplish the same thing with something like:
WITH CTE_PASS AS (
SELECT id
FROM table
WHERE {conditions that mean a pass}
)
SELECT
* ,
CASE WHEN EXISTS (SELECT 1 FROM CTE_PASS WHERE table.id = CTE_CONDITION.id)
THEN 'This ID Passes At Least Somewhere'
ELSE 'This ID never passes'
END as DOES_THIS_EVER_PASS
FROM table

SQL Server condition case doesnt work as intended

I want my SQL to display the overdue count when the condition is the status name showed closed on the exact due date then the count will be set as 1. For example, on the due date, the status name only became closed.
select
category, COUNT(overdue) as overdue2
from
(select
Category, due,
case when DATEDIFF(day, Due, SYSDATETIME()) = 0 then 1
else 0
end as overdue
from
FeedbackDetail
where
StatusName = 'Closed' and
FeedbackDatetime >= '2018-01-01') a
Group by
Category
My expected result is to display the count where the statusname is closed on the exact due date time.
Any idea on this?
The COUNT aggregate function counts existant (non-null) values, so it will count 0 as well as 1. Since you did not post the whole query and we have no idea what a1 is, the only solution that can be proposed is:
Use SUM instead of COUNT.
You can modify the query like given below for better performance and working.
DECLARE #currentDateTime DATETIME = GETDATE()
select
category, SUM(overdue) as overdue2
from
(select
Category,
case when DATEDIFF(day, Due, #currentDateTime) = 0 then 1
else 0
end as overdue
from
FeedbackDetail
where
StatusName = 'Closed' and
FeedbackDatetime >= '2018-01-01') a
Group by
Category

How can I use IF statement in SQL Server in order to show or hide some specific columns

Suppose I have a table like :
(0 means in cash and any other value indicates check serial number)
ID NAME PaymentMethod Amount Bank
------------------------------------------------------------
1 Alex 0 20 ''
2 Sara 123456789 5000 Bank of America
3 Mina 0 15 ''
4 Scott 987456321 10000 Citibank
How can I use an IF statement so that if the PaymentMethod column contains 0 I hide this column and instead show a column with value of Incash and hide the bank column as well.
And when the PaymentMethod is anything else I just rename the column header to CheckSerial.
To make it more clear I want the table to look like this; for those who have paid InCash, it shows up as:
ID NAME PaymentMethod Amount
-------------------------------------------
1 Alex InCash 20
3 Mina InCash 15
for those how have paid by checks, it shows up as :
ID NAME PaymentMethod Serial Number Amount Bank
-------------------------------------------------------------------
2 Sara Check 123456789 5000 Bank of America
4 Scott Check 987456321 10000 Citibank
I tried something like this , based on the given IDs,only one select statement executes:
ALTER FUNCTION dbo.Function1(#IDTag bigint)
RETURNS TABLE
AS
if PaymentMethod = 0
BEGIN
RETURN SELECT ID, Name , PaymentMethod = InCash , Amount
FROM tblTest
WHERE (ID = #IDTag)
END
ELSE
BEGIN
RETURN SELECT ID, Name , PaymentMethod ='By Check', PaymentMethod As [Serial number], Amount, Bank
FROM tblTest
WHERE (ID = #IDTag)
END
Is this even correct?
If this is not feasible or logical what better way can you suggest on this?
You can use the CASE statement to show 'In cash' or 'check' as follows.
select ID, NAME,
CASE PaymentMethod WHEN 0 THEN 'In cash' ELSE 'Check' END as PaymentMethod,
Amount, Bank
from
[mytable]
But you can't hide columns in a single result set, you would need to run two queries
select ID, NAME, 'In cash' PaymentMethod, Amount
from [mytable] where PaymentMethod = 0
and
select ID, NAME, 'Check' PaymentMethod, SerialNumber, Amount, Bank
from [mytable] where PaymentMethod <> 0
You code is not a good plan. The calling program has no way to know what the data is going to look like. Much better to do something like Phil showed where you always return the same table but sometimes some columns are not used.
Also the SQL you show has a number of typos -- you don't have quotes around InCash and you have the same column name (PaymentMethod) twice in the second query.
This is probably the query you want:
SELECT ID, Name,
CASE WHEN PaymentMethod = 0 THEN 'In cash' ELSE 'Check' END as PayBy,
-- NB we could just select PaymentMethod as SerialNumber here, but this is clearer.
CASE WHEN PaymentMethod != 0 THEN PaymentMethod ELSE 0 END as SerialNumber,
Amount, Bank
FROM [mytable]

Issue related to Counting Record on Group by clause

I have one database table having StudentId(int),Subject(varchar(50)),Marks(int),IsPass(int),ExamDate(Datetime)
Table can have more than one record for same Subject for particular student for different Date.
I wrote following query :
select StudentId, Count(IsPass)
from ExamEntry
where IsPass =1 group by StudentId
but dont want Where condition in the Query:
it is Possible something like this :
Select StudentId, case when IsPass = 1 then count(IsPass) end
from ExamEntry
group by studentId
but it display more that one record for perticular studentId
How can i achieve my goal ?
The answer is so simple nobody saw it :-)
SELECT StudentId, SUM(IsPass)
FROM ExamEntry GROUP BY StudentId
SELECT StudentId,
COUNT(CASE WHEN IsPass = 1 THEN 'X' END) AS NumberOfPasses
FROM ExamEntry
GROUP BY StudentId
COUNT only counts NOT NULL values and CASE has an implicit ELSE NULL
Perhaps You need something like this?
SELECT StudentId, SUM(CASE WHEN IsPass = 1 THEN 1 ELSE 0 END) AS Number_Of_Passed_Exams
FROM ExamEntry
GROUP BY StudentId
If you don't want to use where clause for it than Having clause is its simplest alternate.
Try this out.
select StudentId, count(IsPass)AS PassedCount
from ExamEntry
group by StudentId,IsPass
having IsPass= 1

Resources