2

SQL Server Developer Edition 2014

I have a table that looks like:

+ ID + CC +  Xa  +
| 1  | 0  | 53.1 |
| 1  | 1  | 46.1 |
| 1  | 2  | 107.5|
| 2  | 0  | 36.5 |
| 2  | 1  | 41.5 |
| 2  | 2  | 61.8 |

Xa are floats in the table, but I rounded to make it less messy. I had heard of PERCENTILE_DISC from MSDN, and made a query that I thought would give me the median of Xa for each ID:

SELECT DISTINCT s.ExperimentID, 
    PERCENTILE_DISC(.5) WITHIN GROUP( ORDER BY s.Xa) OVER (PARTITION BY s.ExperimentID) 
FROM Simulations s

I threw in the DISTINCT ExperimentID because when I ran the query without it, it was looking to return the median of all ~150M rows for each individual row, which doesn't really make any sense. I did get results, and I think they're right, but I'm not certain. I compared the results of some individual IDs vs what I got from MEDIAN() in LibreOffice, and the results are slightly different. Any idea why?

2 Answers 2

4

Median functions vary in a few ways, particularly when there's an even number of items.

I've blogged about medians, Aaron Bertrand has, Paul White has... I'm in good company. :) I'd recommend you find Aaron's material, which shows better ways to do median than PERCENTILE_CONT.

PERCENTILE_DISC will only choose a value from the list. This is fine if you have an odd number of values, but what if your list is (1, 2, 3, 4)? And then, do you choose 2 or 3? It's valid, but you should define what you need.

If you go with PERCENTILE_CONT, the answer is 2.5.

But if your set is (1, 2, 3, 3) then some would argue that your answer should be weighted by the two threes.

So you should make sure that you've defined what you mean by median. :)

3
  • Very good point! All of my values are distinct, and since I'm fairly simple in my needs, I think a simple AVG of the two middle elements would suit my needs. Is my query okay in that regard? Also, is 6.5 mins an acceptable runtime for such a query (columnstore indexed on 150M rows) Commented Nov 10, 2015 at 20:08
  • @ijustlovemath I don't know how we can determine if 6.5 minutes is an acceptable runtime for your query. Is it acceptable to you? As Rob mentioned, many of us have blogged about median before; I ran some performance tests and determined that - at least in my case - no, the new SQL Server 2012 features were not the fastest. But it might not be true in your case, especially since I didn't test against Columnstore. You could test, though. Commented Nov 10, 2015 at 20:40
  • If you want an average of the two middle values, then DISC isn't want you want. Use CONT instead, but better would be to use a different method for performance reasons.
    – Rob Farley
    Commented Nov 10, 2015 at 21:30
3

It's always a good idea to check your results using a different technique, eg Excel, or if you have access to SQL Server 2016 (CTP 3 at this point) with Advanced Analytics enabled, then you could use R, eg:

-- Use Advanced Analytics Extensions to validate your median calc
EXEC dbo.sp_execute_external_script
    @language = N'R', 
    @script = N'OutputDataSet <- aggregate(InputDataSet$Xa, by=list(InputDataSet$ExperimentID), FUN=median)',
    @input_data_1 = N'SELECT ExperimentID, Xa FROM dbo.Simulations'
WITH RESULT SETS ( ( ExperimentID INT NOT NULL, median FLOAT NOT NULL ) );
GO

Using R to run a median calc in SQL Server

Mainly just for fun, and some exposure to the technique : )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.