Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Data Management

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

Search

XML Feeds

Google Ads

« sp_replwritetovarbin Heap Overflow Code Exploit Code In The Wild, Works By Using Our Good Friend SQL InjectionSQL Friday, The Best SQL Server Links Of The Past Week Episode 3 »
comments
Rate Post:
submit to reddit Digg!FacebookDotnetkicks

Calculating Median and Mode with SQL Server can be frustrating for some developers, but it doesn't have to be. Often times, inexperienced developers will attempt to write this with procedural programming practices, but set based methods do exist.

Before showing you methods to calculate these values, it’s probably best to explain what they are.
Mean is another name for average. SQL Server has a built-in function to calculate this value.

Data
----
1
2
5
5
5
6
6
6
7
9
10

To calculate the average, sum the data and divide by the number of rows. In this case, 1 + 2 + 5 + 5 + 5 + 6 + 6 + 6 + 7 + 9 + 10 = 62. 62/11 = 5.636363

Median represents the 'middle' value. To calculate the median by hand, you sort the values and return the value that appears in the middle of the list. If there is an odd number of items, there will be exactly one value in the middle of the list. If there is an even number of items, you average the 2 values that are closest to the middle.

Data
1
2
5
5
5
6
6
6
7
9
10

Since there is an odd number of rows, the row appearing in the middle of the list contains your median value.

Data
1
2
5
5
5
6
6
6
7
9

Now, there is an even number of rows. The median for this data set is (5 + 6)/2 = 5.5. Simply take the average of the 2 values appearing in the middle of the data set.

MODE
The mode for a data set is the item(s) that appear most frequently. To calculate this by hand, you write a distinct list of values and count the number of times a value appears. The value the appears the most is your mode.

Data	Frequency
----    ---------
1	1
2	1
5	3
6	3
7	1
9	1
10	1

This data set is considered to be Bi-Modal because there are 2 values with the same frequency. With this data set, the modes are 5 and 6.

For demonstration purposes, I will create a table variable and populate it with data. All code will be based on this table variable. The data type for the data column will be Decimal(10,5). If we used an integer column, then we would need to concern ourselves with integer math issues, which is not the focus of this blog.



AVERAGE
As I stated earlier, SQL Server has a built-in function for calculating the average. The Avg function will ignore rows with NULL. So the average of 1, 2, NULL is 1.5 because the sum of the data is 3 and there are 2 rows that are not NULL. 3/2 = 1.5.

  1. DECLARE @Temp TABLE(Id INT IDENTITY(1,1), DATA DECIMAL(10,5))
  2.  
  3. INSERT INTO @Temp VALUES(1)
  4. INSERT INTO @Temp VALUES(2)
  5. INSERT INTO @Temp VALUES(5)
  6. INSERT INTO @Temp VALUES(5)
  7. INSERT INTO @Temp VALUES(5)
  8. INSERT INTO @Temp VALUES(6)
  9. INSERT INTO @Temp VALUES(6)
  10. INSERT INTO @Temp VALUES(6)
  11. INSERT INTO @Temp VALUES(7)
  12. INSERT INTO @Temp VALUES(9)
  13. INSERT INTO @Temp VALUES(10)
  14. INSERT INTO @Temp VALUES(NULL)
  15.  
  16. SELECT AVG(DATA)
  17. FROM   @Temp
  18.  
  19. -- 5.636363




MEDIAN
To calculate the median, we will select the last value in the top 50 percent of rows, and the first value in the bottom 50 percent (all while ignoring NULL values).
To get the last value in the top 50 percent of rows….

		Select Top 1 Data
		From   (
				Select Top 50 Percent Data
				From	@Temp
				Where	Data Is NOT NULL
				Order By Data
				) As A
		Order By Data DESC

To get the first value in the last 50 percent of rows…

		Select Top 1 Data
		From   (
				Select Top 50 Percent Data
				From	@Temp
				Where	Data Is NOT NULL
				Order By Data DESC
				) As A
		Order By Data Asc

Putting it all together:

  1. DECLARE @Temp TABLE(Id INT IDENTITY(1,1), DATA DECIMAL(10,5))
  2.  
  3. INSERT INTO @Temp VALUES(1)
  4. INSERT INTO @Temp VALUES(2)
  5. INSERT INTO @Temp VALUES(5)
  6. INSERT INTO @Temp VALUES(5)
  7. INSERT INTO @Temp VALUES(5)
  8. INSERT INTO @Temp VALUES(6)
  9. INSERT INTO @Temp VALUES(6)
  10. INSERT INTO @Temp VALUES(6)
  11. INSERT INTO @Temp VALUES(7)
  12. INSERT INTO @Temp VALUES(9)
  13. INSERT INTO @Temp VALUES(10)
  14. INSERT INTO @Temp VALUES(NULL)
  15.  
  16. SELECT ((
  17.         SELECT TOP 1 DATA
  18.         FROM   (
  19.                 SELECT  TOP 50 PERCENT DATA
  20.                 FROM    @Temp
  21.                 WHERE   DATA IS NOT NULL
  22.                 ORDER BY DATA
  23.                 ) AS A
  24.         ORDER BY DATA DESC) +
  25.         (
  26.         SELECT TOP 1 DATA
  27.         FROM   (
  28.                 SELECT  TOP 50 PERCENT DATA
  29.                 FROM    @Temp
  30.                 WHERE   DATA IS NOT NULL
  31.                 ORDER BY DATA DESC
  32.                 ) AS A
  33.         ORDER BY DATA ASC)) / 2
  34. -- 6




MODE
To Calculate the mode with sql server, we first need to get the counts for each value in the set. Then, we need to filter the data so that values equal to the count are returned.

  1. DECLARE @Temp TABLE(Id INT IDENTITY(1,1), DATA DECIMAL(10,5))
  2.  
  3. INSERT INTO @Temp VALUES(1)
  4. INSERT INTO @Temp VALUES(2)
  5. INSERT INTO @Temp VALUES(5)
  6. INSERT INTO @Temp VALUES(5)
  7. INSERT INTO @Temp VALUES(5)
  8. INSERT INTO @Temp VALUES(6)
  9. INSERT INTO @Temp VALUES(6)
  10. INSERT INTO @Temp VALUES(6)
  11. INSERT INTO @Temp VALUES(7)
  12. INSERT INTO @Temp VALUES(9)
  13. INSERT INTO @Temp VALUES(10)
  14. INSERT INTO @Temp VALUES(NULL)
  15.  
  16. SELECT TOP 1 WITH ties DATA
  17. FROM   @Temp
  18. WHERE  DATA IS Not NULL
  19. GROUP  BY DATA
  20. ORDER  BY COUNT(*) DESC

As you can see, there are set based methods for calculating all of these values, which can be many times faster than calculating these values in a cursor.

About the Author

George has been developing software professionally for 19 years, first for the department of defense, and then for various other companies. In 1998, George started his software company, Orbit Software, specializing in School Bus Transportation software. His specialty is refining SQL Server queries to deliver optimal performance.
Social SitingsTwitterLTD RSS Feed
13829 views
submit to reddit Digg!FacebookDotnetkicks

Comments and Feedback

8 comments

Comment from: dewitte [Member] Email
*****
Thank you! I run into this all the time and I never remember to take advantage of the top X percent phrase.
07/01/09 @ 09:08
Comment from: Lani Fraizer [Visitor] · http://www.synergiesinsync.org
*****
Very helpful, thanks for posting this!
17/03/09 @ 12:24
Comment from: manish [Visitor]
*****
this is helpful but I made changes to Mode calculation as following..is it any better?

SELECT TOP 1 DATA
FROM @Temp
WHERE DATA IS Not NULL
GROUP BY DATA
ORDER BY COUNT(*) DESC
11/09/09 @ 08:41
Comment from: George Mastros [Member] Email
@manish,

Strictly speaking, your query is not correct because data sets can be multi-modal, which your query does not accommodate.

For example, if you have the following values: 1,2,5,5,5,6,6,6,7,9,10
5 appears 3 times and 6 appears 3 times. This data set is considered multi-modal because there are multiple values that appear in the data set the same number of times.

That being said, a slight modification to your query will return the correct results and execute faster than the query I show.

SELECT TOP 1 WITH TIES DATA
FROM @Temp
WHERE DATA IS Not NULL
GROUP BY DATA
ORDER BY COUNT(*) DESC

Notice the "WITH TIES" addition to your query. This allows multiple rows to be returned where the top 1 value appears in multiple rows.

Thank you for your comment. I will change the query in the blog so that others may benefit from this (without needing to read these comments).
11/09/09 @ 09:07
Comment from: jt [Visitor]
very useful, thx :)
20/11/09 @ 04:15
Comment from: Ben [Visitor]
Very helpful. One suggestion on the mode, however. You probably want a HAVING COUNT(*)>1 in there to account for the fact that some datasets may not have a mode.
04/12/09 @ 09:30
Comment from: Emtucifor [Member] Email
Ben,

Could you give an example of a data set that doesn't have a mode? Consider the data set:

1
2

Isn't the mode [1, 2]?

11/12/09 @ 17:23
Comment from: Lucian [Visitor]
Thank you for the great tip, helped a lot!
23/08/10 @ 08:12

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)