How to case handle a field in Group by - sql

I am trying to group the below CTE based on StudentID and I would like to compute the result with a rule like, if he passes in one subject he is passed overall , if not failed.
WITH mycte(StudentId,SubjectId,Result) as
(SELECT 1,1,'pass'
UNION ALL SELECT 1,2,'fail'
UNION ALL SELECT 1,3,'pass'
UNION ALL SELECT 2,1,'fail'
UNION ALL SELECT 2,2,'fail'
UNION ALL SELECT 3,1,NULL
)
Can you help me in understanding how to achieve this logic.
Expected Result is like
StudentID Result
1 pass
2 fail
3 NULL

Try this simple way
SELECT StudentId,
Result = Max(Result)
FROM mycte
GROUP BY StudentId
Trick here is Pass will be ordered after Fail in string ordering. So when you use Max aggregate we will get Pass if at least one Pass is present

You can aggregate over students and count the number of passes. According to your logic, if even one pass is seen then the student should be reckoned as passing overall.
SELECT DISTINCT
t1.StudentId,
t2.Result
FROM mycte t1
LEFT JOIN
(
SELECT
StudentId,
CASE WHEN SUM(CASE WHEN Result = 'pass' THEN 1 ELSE 0 END) > 0
THEN 'pass'
WHEN SUM(CASE WHEN Result = 'fail' THEN 1 ELSE 0 END) > 0
THEN 'fail'
ELSE NULL END AS Result
FROM mycte
GROUP BY StudentId
) t2
ON t1.StudentId = t2.StudentId

Related

Select statement with a condition on multiple entries

Following is my table:
I want to create a view with the following conditions in a select statement:
If count(employee_id) > 1 then only the record having status = 'Current' is picked in the view.
I tried:
select employee_id
, case when COUNT(employee_id) > 1 and statusval = 'Current' then 'Y' else 'N' end as val
from table1
group by employee_id
I hope someone can help me with this statement. Thanks.
Try this
DECLARE #T TABLE (ID INT, STATUS VARCHAR(50))
INSERT INTO #T VALUES (1,'Current'),(2,'Historical'),(2,'Historical'),(2,'Current')
SELECT * FROM #T M
INNER JOIN (SELECT ID FROM #T
GROUP BY ID
HAVING COUNT(ID) > 1) S ON S.ID=M.ID
WHERE M.STATUS = 'Current'
Just to show you how your attempt could have looked. You were nearly there, you just needed to use the windowed version of count e.g.
with cte as (
select Employee_Id, [Status]
, case when count(*) over (partition by id) > 1 and [Status] = 'Current' then 1 else 0 end Val
from Table1
)
select Employee_Id, [Status]
from cte
where Val = 1;
And this approach appears on the face of it to perform better than a join.
All of your sample data have exactly one row with 'Current'. So, the simplest solution appears to be:
select t.*
from t
where t.status = 'Current';

Is it possible to put a row with specific data at row number one in SQL?

Assume i have a table:
I want that row with UserId ='ee' always display at row number one every time i select this table in SQLQuery.
Is it possible?
select *
from your_table
order by UserId <> 'ee' -- "<>", because false < true
or (arguably clearer):
select *
from your_table
order by case when UserId = 'ee' then 0 else 1 end
Use a view:
CREATE VIEW myView AS
SELECT * FROM myTable ORDER BY (case when UserId = 'ee' then 0 else 1 end) ASC
You can use the CASE Clause or IF Clause to change to order.
Example:
SELECT * FROM
Table
ORDER BY (CASE WHEN UserID = 'ee' THEN 1 ELSE 2 END) ASC, UserID ASC
Or
SELECT * FROM
Table
ORDER BY IIF(UserID = 'ee', 1, 2) ASC, UserID ASC
This way you give te ee value number 1 and all the others number 2 and order by those numbers. When those are ordered you order the duplicated 2's by the UserID itself.

How to get join multiple queries

In this http://sqlfiddle.com/#!6/aa0e17/4 as you can see id is primary key and auto incremented and values column is int type. To retrieve count based on value I am doing 4 different queries
select count(id) from status where value=1
select count(id )from status where value=2
select count(id) from status where value=3
select count(id) from status where value=4
My requirement is to get all those counts in a single query.
Why I want?
The above table is just a demo table and have only 4 queries but in my scenario I have 35 queries and so I have to do 35 methods in java.
Expected output: 4,,4,4,4 (1st query result, 2nd query result, 3rd query result, 4th query result)
select value, count(id)
from status
group by value
Here are the 2 normal ways of solving it:
Example 1 PIVOT:
SELECT [1] count1,[2] count2,[3] count3,[4] count4
FROM
(
SELECT id, value
FROM status
) p
PIVOT (COUNT(id) FOR [value] IN ([1], [2], [3], [4])) AS pvt
Use CONCAT if you want to combine the columns into one.
To do this, replace first row in first example with:
SELECT CONCAT([1],',',[2],',',[3],',',[4])
Example 2 CASE:
SELECT
COUNT(CASE WHEN value = 1 THEN 1 END) count1,
COUNT(CASE WHEN value = 2 THEN 1 END) count2,
COUNT(CASE WHEN value = 3 THEN 1 END) count3,
COUNT(CASE WHEN value = 4 THEN 1 END) count4
FROM status
You should better count rows and group by the value by the following query:
SELECT COUNT(*) FROM status GROUP BY value
or for a better description and look try this:
SELECT value, COUNT(*) AS COUNT FROM status GROUP BY value
Use UNION (or UNION ALL to preserve duplicate values) like:
select count(id) from status where value=1
UNION
select count(id )from status where value=2
UNION
select count(id) from status where value=3
UNION
select count(id) from status where value=4
Have a look at a similar question here: https://stackoverflow.com/a/6066234
[Edit 1]
Check the fiddle, it works on my machine ;) http://sqlfiddle.com/#!6/b89ef/1/0
Since I removed a (3) from the insert, you get 4,3 (I'm only selecting fours and threes here).
[Edit 2]
I did not catch the part where you wanted it all on one line.
Just wrap a SELECT around your statements like http://sqlfiddle.com/#!6/aa0e17/34/0:
select
(select count(id) from status where value=1),
(select count(id) from status where value=2),
(select count(id) from status where value=3),
(select count(id) from status where value=4)
;
And your result is one row with 4,4,4,4 as result.
If what you're looking for is a comma-delimited string, then this might be helpful:
WITH CTE(N) AS(
SELECT COUNT(ID) FROM STATUS WHERE VALUE=1 UNION ALL
SELECT COUNT(ID )FROM STATUS WHERE VALUE=2 UNION ALL
SELECT COUNT(ID) FROM STATUS WHERE VALUE=3 UNION ALL
SELECT COUNT(ID) FROM STATUS WHERE VALUE=4 UNION ALL
)
SELECT STUFF((
SELECT N', ' + CONVERT(VARCHAR(10), N)
FROM CTE FOR XML PATH(''), TYPE
).value('text()[1]','nvarchar(max)')
, 1 , 2 , N'')

TSQL Count Case When In

I am having trouble with some logic here. Trying to get a count of rows where S.ID's not in my subquery.
COUNT(CASE WHEN S.ID IN
(SELECT DISTINCT S.ID FROM...)
THEN 1 ELSE 0 END)
I am recieving the error:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
How to fix this or an alternative?
Maybe something like this?
SELECT COUNT(*) FROM .... WHERE ID NOT IN (SELECT DISTINCT ID FROM ...)
Using EXISTS :
SELECT COUNT(t.*) FROM table1 t WHERE NOT EXISTS (SELECT * FROM table2 WHERE ID = t.ID)
Use following construct with CTE.
with cte as
(
select
case
when S.ID in (SELECT DISTINCT S.ID FROM LookupTable) then 1
else 0
end
as SID
from MyTable)
select count(SID) as SIDCOUNT from cte;

Merge two SELECT queries into one

I have two queries where I only need the count of total records but the only difference in the queries is one field value.
Example;
SELECT COUNT(*) AS group_a
FROM tbl
WHERE category = 'value_a'
SELECT COUNT(*) AS group_b
FROM tbl
WHERE category = 'value_b'
How can I get something like this: (pseudo)
SELECT COUNT(*) AS group_a, COUNT(*) AS group_b
FROM tbl
WHERE category IN ('value_a', 'value_b')
But the results are like this
group_a , group_b
56, 101
I was thinking a CASE statement in the query to filter the two but how do I implement it? or is there a better way?
I'm doing a UNION right now but wanted to know if I could return one record with two results
select sum(case when category = 'value_a' then 1 else 0 end) as group_a,
sum(case when category = 'value_b' then 1 else 0 end) as group_b
from tbl
where category in ('value_a', 'value_b')
select sum(case when category = 'value_a' then 1 else 0 end) group_a,
sum(case when category = 'value_b' then 1 else 0 end) group_b
from tbl
SELECT category,COUNT(*) FROM tbl
GROUP BY category;
That expands to more categories. If you want just those categories
SELECT category,COUNT(*) FROM tbl
WHERE category IN ('value_a', 'value_b')
GROUP BY category;
What strange answers for counting. Here's a straightforward COUNT:
SELECT COUNT(category = 'value_a' OR NULL) AS group_a, COUNT(category = 'value_b' OR NULL) AS group_b FROM tbl;
The COUNT aggregate in PostgreSQL allows complex syntax like I've shown. Note that the OR NULL is quite essential as COUNT counts only those rows for which the condition category = '...' OR NULL gives non-NULL answer.
Just for the fun of it:
SELECT *
FROM
(
SELECT category
FROM tbl
) subquery
PIVOT
(
COUNT(category)
FOR category IN ([value_a],[value_b])
) AS piv