How to count all distinct rows? - sql

If I have a table like below, how can I count and sum all distinct values?
student_name | section | score | class
-------------|---------|-------|-------
John | B | 32 | 8
Doe | B | 43 | 8
Jane | A | 33 | 8
Smith | A | 88 | 8
Pat | B | 99 | 9
The output I desire is following for each class. So for class 8 it would be:
section | num_records | score_total
---------|--------------|-------------
B | 2 | 75
A | 2 | 121
Total | 4 | 196

You could use GROUPING SETS:
SELECT COALESCE(section, 'Total') AS section,
COUNT(*) AS num_records,
SUM(score) AS score_total
FROM t
WHERE class = 8
GROUP BY GROUPING SETS (section, ())
ORDER BY section;
db<>fiddle demo

you could use union all and subquery
select section,count(*),sum(score)
from t
where class =8
group by section
union all
select 'Total',count(*),sum(score) from t
where class=8
demo
output
section count sum
A 2 121
B 2 75
Total 4 196

Related

Generate 'average' column from sub query and ROW_NUMBER window function in SQL SELECT

I have the following SQL Server tables (with sample data):
Questionnaire
id | coachNodeId | youngPersonNodeId | complete
1 | 12 | 678 | 1
2 | 12 | 52 | 1
3 | 30 | 99 | 1
4 | 12 | 678 | 1
5 | 12 | 678 | 1
6 | 30 | 99 | 1
7 | 12 | 52 | 1
8 | 30 | 102 | 1
Answer
id | questionnaireId | score
1 | 1 | 1
2 | 2 | 3
3 | 2 | 2
4 | 2 | 5
5 | 3 | 5
6 | 4 | 5
7 | 4 | 3
8 | 5 | 4
9 | 6 | 1
10 | 6 | 3
11 | 7 | 5
12 | 8 | 5
ContentNode
id | text
12 | Zak
30 | Phil
52 | Jane
99 | Ali
102 | Ed
678 | Chris
I have the following T-SQL query:
SELECT
Questionnaire.id AS questionnaireId,
coachNodeId AS coachNodeId,
coachNode.[text] AS coachName,
youngPersonNodeId AS youngPersonNodeId,
youngPersonNode.[text] AS youngPersonName,
ROW_NUMBER() OVER (PARTITION BY Questionnaire.coachNodeId, Questionnaire.youngPersonNodeId ORDER BY Questionnaire.id) AS questionnaireNumber,
score = (SELECT AVG(score) FROM Answer WHERE Answer.questionnaireId = Questionnaire.id)
FROM
Questionnaire
LEFT JOIN
ContentNode AS coachNode ON Questionnaire.coachNodeId = coachNode.id
LEFT JOIN
ContentNode AS youngPersonNode ON Questionnaire.youngPersonNodeId = youngPersonNode.id
WHERE
(complete = 1)
ORDER BY
coachNodeId, youngPersonNodeId
This query outputs the following example data:
questionnaireId | coachNodeId | coachName | youngPersonNodeId | youngPersonName | questionnaireNumber | score
1 | 12 | Zak | 678 | Chris | 1 | 1
2 | 12 | Zak | 52 | Jane | 1 | 3
3 | 30 | Phil | 99 | Ali | 1 | 5
4 | 12 | Zak | 678 | Chris | 2 | 4
5 | 12 | Zak | 678 | Chris | 3 | 4
6 | 30 | Phil | 99 | Ali | 2 | 2
7 | 12 | Zak | 52 | Jane | 2 | 5
8 | 30 | Phil | 102 | Ed | 1 | 5
To explain what's happening here… There are various coaches whose job is to undertake questionnaires with various young people, and log the scores. A coach might, at a later date, repeat the questionnaire with the same young person several times, hoping that they get a better score. The ultimate goal of what I'm trying to achieve is that the managers of the coaches want to see how well the coaches are performing, so they'd like to see whether the scores for the questionnaires tend to go up or not. The window function represents a way to establish how many times the questionnaire has been undertaken by the same coach/young person combo.
I need to be able to determine the average score based on the questionnaire number. So for example, the coach 'Zak' logged scores of '1' and '3' for his first questionnaires (where questionnaireNumber = 1) so the average would be 2. For his second questionnaires (where questionnaireNumber = 2) the scores were '3' and '5' so the average would be 4. So in analysing this data we know that over time Zak's questionnaire scores have improved from an average of '2' the first time to an average of '4' the second time.
I feel like the query needs to be grouped by the coachNodeId and questionnaireNumber values so it would output something like this (I've ommitted the questionnaireId, youngPersonNodeId, youngPersonName and score columns as they aren't crucial for the output — they're only used to derive the averageScore — and wouldn't be useful the way the results are grouped):
coachNodeId | coachName | questionnaireNumber | averageScore
12 | Zak | 1 | 2 (calculation: (1 + 3) / 2)
12 | Zak | 2 | 4 (calculation: (3 + 5) / 2)
12 | Zak | 3 | 4 (only one value: 4)
30 | Phil | 1 | 5 (calculation: (5 + 5) / 2)
30 | Phil | 2 | 2 (only one value: 2)
Could anyone suggest how I can modify my query to output the average scores based on the score from the sub-query and the ROW_NUMBER window function? I've hit the limits of my SQL skills!
Many thanks.
It is a bit hard to tell without sample data, but I think you are describing aggregation:
SELECT q.coachNodeId AS coachNodeId,
cn.[text] AS coachName,
q.youngPersonNodeId AS youngPersonNodeId,
ypn.[text] AS youngPersonName,
AVG(score)
FROM Questionnaire q JOIN
ContentNode cn
ON q.coachNodeId = cn.id JOIN
ContentNode ypn
ON q.youngPersonNodeId = ypn.id LEFT JOIN
Answer a
ON a.questionnaireId = q.id
WHERE complete = 1
GROUP BY q.coachNodeID, cn.[text] AS coachName,
q.youngPersonNodeId, ypn.[text]

Selecting a column such as a player only once first by a max value then by a min value

So I've two tables 'AllBowlRecords' and one 'AggregateBowlRecords'
AllBowlRecords :-
plr_fullnm|Wkts|Runs
---------------------
Bumrah | 4 | 23
Bumrah | 2 | 7
Bumrah | 1 | 51
Bumrah | 4 | 39
Jason | 3 | 48
Jason | 3 | 29
Jason | 3 | 70
So all I want is to update AggregateBowlRecords based on AllBowlRecords where Wkts is MAX, but if there's multiple occurrences of MAX Wkts value, then whichever corresponds minimum runs should be selected. And AggregateBowlRecords should look like this:
Bumrah | 4 | 23
Jason | 3 | 29
What are the possible solutions?
You can return the results you want using a query with row_number():
select plr_fullnm, Wkts, Runs
from (select abr.*,
row_number() over (partition by plr_fullnm order by wkts desc, runs) as seqnum
from AllBowlRecords abr
) abr
where seqnum = 1;

Join multiple select queries SQL

I have two queries with different where clauses,and I need to join both the query to get a single result table.
First query:
SELECT
players.id,player_name,count(matches.winner) as wintotal
FROM
matches, players
WHERE
matches.winner = players.id
GROUP BY
players.id;
It returns these results:
id | player_name | wintotal
45 | Vijay | 2
43 | Rahul | 1
46 | Shinoy | 1
48 | Sunil | 2
44 | Adarsh | 4
Second query :
SELECT
players.id, player_name, count(*) as totalgames
FROM
matches, players
WHERE
matches.winner = players.id or matches.loser = players.id
GROUP BY
players.id;
Returns:
id | player_name | Total Matches
45 | Vijay | 4
43 | Rahul | 2
46 | Shinoy | 4
48 | Sunil | 2
44 | Adarsh | 6
47 | Pranjal | 2
In these two queries, the where clause is different for both queries and the last column is different.
First query returns total wins by players
Second query returns total matches played by player
How can I join both queries to get both columns wins and total matches in single query?
Expected output:
id | player_name | Total Matches | wintotal
45 | Vijay | 4 | 2
43 | Rahul | 2 | 1
46 | Shinoy | 4 | 1
48 | Sunil | 2 | 2
44 | Adarsh | 6 | 4
47 | Pranjal | 2 | 0
Thanks
try:
select players.id,
player_name,
count(case when matches.winner=players.id then 1 end) as wintotal ,
count(*) as totalgames
from matches
join players
on matches.winner=players.id or matches.loser=players.id
group by players.id,
player_name;
Check This.
select id , player_name ,Total_Matches , wintotal
(
select players.id,player_name,count(matches.winner) as wintotal from matches,players where matches.winner=players.id
group by players.id
) A,
(
select players.id,player_name,count(*) as Total_Matches from matches,players where matches.winner=players.id or
matches.loser=players.id
group by players.id
) B
where A.id=B.ID

Sum multiple columns based on criteria from other columns - SQL Teradata

I would like to get a total of the scores from columns 3 & 4 for each of the counties in columns 1 & 2 from the table shown below:
County1 | County2 | Player1_Score | Player2_Score
Norfolk | Hampshire | 5 | 7
Suffolk | Norfolk | 10 | 6
Hampshire | Suffolk | 16 | 12
Norfolk | Suffolk | 78 | 50
Hampshire | Norfolk | 4 | 8
Suffolk | Hampshire | 9 | 19
So the results I would like to see would be as follows:
Norfolk | 97
Suffolk | 77
Hampshire | 32
Can anyone please help with this? I tried a SELECT/GROUP BY query but am fairly new to SQL and couldn't get the results I wanted.
Many thanks
Try this:
SELECT County, SUM(Score) AS TotalScore
FROM (
SELECT County1 AS County, Player1_Score AS Score
FROM mytable
UNION ALL
SELECT County2, Player2_Score
FROM mytable) AS t
GROUP BY County
ORDER BY TotalScore DESC
Demo here
SEL CNTRY,SUM(SUM1) FROM
(
SEL COUNTRY1 AS CNTRY, SUM(player_score_1) AS SUM1 FROM VT1
GROUP BY 1
UNION
SEL COUNTRY2 AS CNTRY, SUM(player_score_2) FROM VT1
GROUP BY 1
) A
GROUP BY 1

SQL Server 2008 - accumulating column

I would like to accumulate my data as you can see below there is origin table table1:
What is the best query for to do this?
Is possible to do this dynamically - when I add more types of terms??
Table 1
ID | term | value
-----------------------
1 | I | 100
2 | I | 200
3 | II | 100
4 | II | 50
5 | II | 75
6 | III | 50
7 | III | 65
8 | IV | 30
9 | IV | 45
And the result should be like below:
YTD | Acc Value
------------------
I-I | 300
I-II | 525
I-III| 640
I-IV | 715
Thanks
select
(select min(term) from yourtable ) +'-'+term,
(select sum(value) from yourtable t1 where t1.term<=t.term)
from yourtable t
group by term