Getting the count of resultset along with result rows - sql

I have a SQL query for which I needed to have result rows count and results as the output of query.
For example,
SELECT count(*) total, id, name, age, grade
FROM Employee
where grade = 10;
It prints only one row with total count.
Please let me know what could be missing in query.
With GROUP BY:
Table:
id name age grade
1 ABC 30 10
2 DEF 31 10
3 GHI 29 6
4 PQR 29 10
Query:
SELECT count(*) total, id, name, age, grade
FROM Employee
where grade = 10
group by id, name, age, grade
total id name age grade
1 1 ABC 30 10
1 2 DEF 31 10
1 4 PQR 29 10
Under total, I expect to have 3 as the value although it will be repeated.
Here my intention is to have total row count and result rows as part of single query.

Perhaps a GROUP BY is what you want?
SELECT count(*) total, id, name, age, grade
FROM Employee
where grade = 10
group by id, name, age, grade

SQLite computes result rows on the fly, so it does not know the size of the result set until you have fetched the last row.
If possible, change your program so that it just can count the rows.
If you really want to have the row count in every row, you have to compute it separately:
SELECT (SELECT COUNT(*)
FROM Employee
WHERE grade = 10
) AS total,
id, name, age, grade
FROM Employee
WHERE grade = 10;

Try this
SELECT * FROM
((SELECT COUNT(*) as total FROM EMPLOYEES
WHERE grade = 10)
CROSS JOIN
(SELECT id, name, age, grade
FROM Employee
where grade = 10))

Related

SQL: Efficient way to get group by results including all table columns

Let's consider a simple table below.
id
code
marks
grade
1
X
100
A
2
Y
120
B
3
Z
130
A
4
X
120
C
5
Y
100
A
6
Z
110
B
7
X
150
A
8
X
140
C
Goal: Get maximum marks for each grade, return all the columns.
id
code
marks
grade
7
X
150
A
2
Y
120
B
8
X
140
C
This is very simple if I don't want id and code column
select grade, max(marks)
from table
group by grade;
What could be the most efficient query to get id and code column in the above query?
I tried something like this which didn't work
select * from table t
inner join
(select grade, max(marks)
from table
group by grade) a
on a.grade=t.grade;
In Postgres the most efficient way for this kind of query is to use (the proprietary) distinct on ()
select distinct on (grade) *
from the_table t
order by grade, marks desc;
Are you looking for a correlated subquery?
select t.*
from t
where t.marks = (select max(t2.marks) from t t2 where t2.grade = t.grade);

Postgres SQL GROUP BY depending on a value from another column

I am trying to query set result set which returns something like the below.
I need to return only 1 row per name and need to GROUP BY but only the name that have a value of '8' under the Grade column are desired. The below is a result from another query. Because Sandra has a different value other than 8, Sandra should be omitted.
eg:- In the below I need to get one row for John only.
Please advise. Thank you.
Name Grade
======= =====
Sandra 8
Sandra 8
Sandra 8
Sandra 9
John 8
John 8
John 8
John 8
Expected Result - 1 row
Name Grade
John 8
Aggregate your table on the name, and then use a HAVING clause to filter out names which have a grade other than 8 (or any other values which you do not want).
SELECT name, MIN(grade) AS grade
FROM yourTable
GROUP BY name
HAVING SUM(CASE WHEN grade <> 8 THEN 1 ELSE 0 END) = 0;
Demo
Update:
If the grade column were text, and you wanted to compare against the string '8' instead of a number, then you could use this HAVING clause:
HAVING SUM(CASE WHEN grade <> '8' THEN 1 ELSE 0 END) = 0;
If you want names that have only 8s, you can do:
select name
from t
group by name
having min(grade) = max(grade) and min(grade) = 8;
Alternately,
SELECT DISTINCT B.name, B.grade
FROM
(
SELECT name FROM yourTable GROUP BY name HAVING COUNT(DISTINCT grade) = 1
) Z
INNER JOIN
yourTable B
ON Z.name = B.name
AND B.grade = 8;

Sort by aggregate value in sql

Let's say I have the following student data:
classroom gender student_id
-------------------------------------
First Grade M 123
First Grade F 124
First Grade F 125
Second Grade M 126
Third Grade M 127
...
I want to produce the following result: top 3 biggest classrooms ordered by total number of students with detail for each:
classroom boys_count girls_count total_count
--------------------------------------------------
Third Grade 30 30 60
First Grade 20 5 25
Fourth Grade 10 10 20
How can I do that in sql ? If necessary, I can use specific postrges features.
What I tried so far:
SELECT count(*) as total_count
, gender
, classroom
ORDER BY 1
GROUP BY classroom, gender
LIMIT 3
Then I re-organise results in some scripting language. But this is too slow. I want to have the correct results with one query
select classroom as name,
sum(case when gender = 'M' then 1 else 0 end) as boys_count,
sum(case when gender = 'F' then 1 else 0 end) as girls_count,
count(*) as total_count
from your_table
group by classroom
order by count(*) desc
limit 3

How to find number of failed grades and the number of general average?

I have A table of students and their grades.
How can I count the number of failed grades (<50)
and find the general average ( I mean the average for every student ) using sqlite?
this is the table (studentTable):
sID LessonID grade
1 1 45
1 2 50
1 3 65
2 1 44
2 2 22
2 3 91
I expect the results like this:
sID noOfFails Average
1 1 53
2 2 5
Try
SELECT
sID,
SUM(CASE WHEN grade < 50 THEN 1 ELSE 0 END) AS noOfFails,
AVG(grade) AS Average
FROM studentTable
GROUP BY sID
Demo at http://sqlfiddle.com/#!5/fcd13/1
You could use a case expression inside the count function:
SELECT sID, COUNT(CASE WHEN grade < 50 THEN 1 END) AS noOfFails, AVG(grade)
FROM mytable
You can simply run it as follows:
SELECT sID, COUNT(IIF(grade<50,1,NULL)) as noOfFails, AVG(grade) as Average
FROM studentTable GROUP BY sID

Count without nested select: is this possible?

Database:
Department Position Points
A Manager 50
A Supervisor 10
A Supervisor 10
A Staff 2
A Staff 2
B Manager 40
B SuperVisor 8
B Staff 2
B Staff 2
B Staff 2
Desired query result:
Dept Manager Count Supervisor Count Staff Count Staff Total Pts
A 1 2 2 4
B 1 1 3 4
Is the desired query result possible without using nested select with count?
We have a certain stored procedure similar to this using nested counts and we like to make it simpler and perform better/faster
Use Conditional Aggregate to count only the specific data
Select Department,
count(case when Position = 'Manager' then 1 END) as Manager,
count(case when Position = 'Supervisor' then 1 END) as Supervisor,
count(case when Position = 'Staff' then 1 END) as Staff
From yourtable
Group by Department
If you are using Sql Server use this
SELECT Department,
Manager,
Supervisor,
Staff
FROM Yourtable
PIVOT (Count(Position)
FOR Position IN (Manager,Supervisor,Staff))pv
Use conditional SUM:
SELECT Department,
SUM(CASE WHEN Position = 'Manager' THEN 1 END) as Manager,
SUM(CASE WHEN Position = 'Supervisor' THEN 1 END) as Supervisor,
SUM(CASE WHEN Position = 'Staff' THEN 1 END) as Staff
FROM yourtable
GROUP BY Department
Or You can use PIVOT operator:
select Detartment, Manager, Supervisor, Staff
from yourtable
pivot (count(Position) for Position in (Manager, Supervisor, Staff)) Result