Select and group by two columns - sql

I have a table that stores the number of users who score in a particular range. I am trying to design a query that will show the total number of students who scored in that range. The table has repetitions since its a log table. here is there table
Here is my query
select id, min, max, count(Score)
from Scorelogs
I know I have to use "COUNT" in the query but I don't know how to group by the min and max.

You want to just group by the range:
select "min", "max", sum(score)
from data
group by "min", "max"
order by 1, 2;
Note that min and max are very poor names for columns, because they conflict with the built in functions that have the same names.

Use as , In this scenerio id is not generated.
select min,max, count(Score) from Scorelogs group by min,max
Or you can use
select ROW_NUMBER()
OVER (ORDER BY max) AS id, min,max, count(Score) from Scorelogs group by min,max

SELECT ROW_NUMBER() OVER(ORDER BY min,max) as id,
min,
max,
SUM(Score)
FROM Scorelogs
GROUP BY min,max
Fiddle Demo

Related

Is there a way to get percentage for earch field

I need percentage for each status
Select NAME, STATUS, Count(*) From DATA
group by NAME, STATUS
order by NAME
You need to create subquery for count without status, then you need to get percentage user wise, you can try this below:
Select f1.NAME, f1.STATUS, Count(*),CONCAT((Count(*)*100)/(select Count(*) from data f2 where NAME=f1.Name group by f2.NAME),'%') From DATA f1
group by f1.NAME, f1.STATUS
order by f1.NAME
Or if you have user id then it's better query and perfect result
Select f1.NAME, f1.STATUS, Count(*),CONCAT((Count(*)*100)/(select Count(*) from data f2 where UserId=f1.UserId group by f2.UserId),'%') From DATA f1
group by f1.UserId,f1.NAME, f1.STATUS
order by f1.NAME
I think you have used below formula in your percentage calculate,
count(row first count)*100/sum of all count rows, i.e.448*100/1560=28.71.
So, dear, I request you please mention all the problems with your question.
Try the below query and enjoy it.
Select NAME, STATUS, Count(*),
Count(*)*100/(select sum(CT) from (select NAME, STATUS, Count(*) CT from data group by NAME, STATUS))PERCENTAGE
From DATA
group by NAME, STATUS
order by NAME
Here's how to get the percentage. First is to get the total count(), then multiple by 1.0, to cast the result in decimal format.
select name, status, count(1)
, ((count(1) * 1.0)
/(select count(1) from data)) * 100 as percentage
from data
group by name, status
order by name
Check this, using SUM to calculate the total and then use group by to group the names
SELECT name, status, COUNT(status)/(
SELECT COUNT(status)
FROM data
)*100
FROM percentage
GROUP BY name, status
ORDER BY name

Average without grouping or subquery

I realize this is an odd question, but I'd like to know if this is possible.
Let's say I have a DB with ages and IDs. I need to compare each ID's age to the average age, but I can't figure out how to do that without grouping or subqueries.
SELECT
ID,
AGE - AVG(AGE)
FROM
TABLE
I'm trying to get something like the above, but obviously that doesn't work because ID isn't grouped, but I group, then it calculates the average for each group, and not the table as a whole. How can I get a global average without a subquery?
SELECT ID,
AGE -
AVG(AGE) OVER (partition by ID) as age_2
FROM Table
I just read is global avg
SELECT ID,
AGE -
AVG(AGE) OVER () as age_2
FROM Table
The window logic for average age is:
SELECT ID, AGE - ( AVG(AGE) OVER () )
FROM TABLE;
You do not want ORDER BY in the partitioning clause.
How can I get a global average without a subquery?
Use a variable.
DECLARE #AvgAge decimal(4,3)
SELECT #AvgAge = AVG(AGE) FROM TABLE
SELECT ID, AGE - #AvgAge [AgeDiff] FROM TABLE

I need the Top 10 results from table

I need to get the Top 10 results for each Region, Market and Name along with those with highest counts (Gaps). There are 4 Regions with 1 to N Markets. I can get the Top 10 but cannot figure out how to do this without using a Union for every Market. Any ideas on how do this?
SELECT DISTINCT TOP 10
Region, Market, Name, Gaps
FROM
TableName
ORDER BY
Region, Market, Gaps DESC
One approach would be to use a CTE (Common Table Expression) if you're on SQL Server 2005 and newer (you aren't specific enough in that regard).
With this CTE, you can partition your data by some criteria - i.e. your Region, Market, Name - and have SQL Server number all your rows starting at 1 for each of those "partitions", ordered by some criteria.
So try something like this:
;WITH RegionsMarkets AS
(
SELECT
Region, Market, Name, Gaps,
RN = ROW_NUMBER() OVER(PARTITION BY Region, Market, Name ORDER BY Gaps DESC)
FROM
dbo.TableName
)
SELECT
Region, Market, Name, Gaps
FROM
RegionsMarkets
WHERE
RN <= 10
Here, I am selecting only the "first" entry for each "partition" (i.e. for each Region, Market, Name tuple) - ordered by Gaps in a descending fashion.
With this, you get the top 10 rows for each (Region, Market, Name) tuple - does that approach what you're looking for??
I think you want row_number():
select t.*
from (select t.*,
row_number() over (partition by region, market order by gaps desc) as seqnum
from tablename t
) t
where seqnum <= 10;
I am not sure if you want name in the partition by clause. If you have more than one name within a market, that may be what you are looking for. (Hint: Sample data and desired results can really help clarify a question.)

sql query finding most often level appear

I have a table Student in SQL Server with these columns:
[ID], [Age], [Level]
I want the query that returns each age value that appears in Students, and finds the level value that appears most often. For example, if there are more 'a' level students aged 18 than 'b' or 'c' it should print the pair (18, a).
I am new to SQL Server and I want a simple answer with nested query.
You can do this using window functions:
select t.*
from (select age, level, count(*) as cnt,
row_number() over (partition by age order by count(*) desc) as seqnum
from student s
group by age, level
) t
where seqnum = 1;
The inner query aggregates the data to count the number of levels for each age. The row_number() enumerates these for each age (the partition by with the largest first). The where clause then chooses the highest values.
In the case of ties, this returns just one of the values. If you want all of them, use rank() instead of row_number().
One more option with ROW_NUMBER ranking function in the ORDER BY clause. WITH TIES used when you want to return two or more rows that tie for last place in the limited results set.
SELECT TOP 1 WITH TIES age, level
FROM dbo.Student
GROUP BY age, level
ORDER BY ROW_NUMBER() OVER(PARTITION BY age ORDER BY COUNT(*) DESC)
Or the second version of the query using amount each pair of age and level, and max values of count pair age and level per age.
SELECT *
FROM (
SELECT age, level, COUNT(*) AS cnt,
MAX(COUNT(*)) OVER(PARTITION BY age) AS mCnt
FROM dbo.Student
GROUP BY age, level
)x
WHERE x.cnt = x.mCnt
Demo on SQLFiddle
Another option but will require later version of sql-server:
;WITH x AS
(
SELECT age,
level,
occurrences = COUNT(*)
FROM Student
GROUP BY age,
level
)
SELECT *
FROM x x
WHERE EXISTS (
SELECT *
FROM x y
WHERE x.occurrences > y.occurrences
)
I realise it doesn't quite answer the question as it only returns the age/level combinations where there are more than one level for the age.
Maybe someone can help to amend it so it includes the single level ages aswell in the result set: http://sqlfiddle.com/#!3/d597b/9
with combinations as (
select age, level, count(*) occurrences
from Student
group by age, level
)
select age, level
from combinations c
where occurrences = (select max(occurrences)
from combinations
where age = c.age)
This finds every age and level combination in the Students table and counts the number of occurrences of each level.
Then, for each age/level combination, find the one whose occurrences are the highest for that age/level combination. Return the age and level for that row.
This has the advantage of not being tied to SQL Server - it's vanilla SQL. However, a window function like Gordon pointed out may perform better on SQL Server.

Calculate max, average of some row sql

i've a table like:
i have to make sql query to get the average of v and order the average to have the #n best name in function of v in time. Users so have to select #n of best that want to have before do this query.
In order to have:
Can someone help me?
You don't need average, you need SUM
SELECT name, SUM(v) AS sum FROM table GROUP BY name ORDER BY SUM(v) DESC
Use:
select name, sum(v) as average
from table
group by name
order by sum(v) desc
select avg(average),name from tableName group by name order by avg(average) desc