Согласно MSDN , Медиана недоступна как агрегатная функция в Transact-SQL. Однако я хотел бы выяснить, возможно ли создать эту функцию (используя функцию « Создать агрегат» , пользовательскую функцию или какой-либо другой метод).
Каков наилучший способ (если это возможно) сделать это - разрешить вычисление медианного значения (принимая числовой тип данных) в агрегированном запросе?
sql
sql-server
aggregate-functions
median
Яаков Эллис
источник
источник
Ответы:
ОБНОВЛЕНИЕ 2019: За 10 лет, с тех пор как я написал этот ответ, было найдено больше решений, которые могут дать лучшие результаты. Кроме того, выпуски SQL Server с тех пор (особенно SQL 2012) представили новые функции T-SQL, которые можно использовать для вычисления медиан. В выпусках SQL Server также улучшен оптимизатор запросов, который может влиять на различные срединные решения. Net-net, мой оригинальный пост за 2009 год все еще в порядке, но могут быть более эффективные решения для современных приложений SQL Server. Взгляните на эту статью 2012 года, которая является отличным ресурсом: https://sqlperformance.com/2012/08/t-sql-queries/median
Эта статья обнаружила, что следующий шаблон намного, намного быстрее, чем все другие альтернативы, по крайней мере, на простой проверенной схеме. Это решение было в 373 раза быстрее (!!!), чем самое медленное (
PERCENTILE_CONT
) из протестированных. Обратите внимание, что этот прием требует двух отдельных запросов, которые могут быть не практичными во всех случаях Это также требует SQL 2012 или позже.Конечно, только из-за того, что один тест на одной схеме в 2012 году дал отличные результаты, пробег может отличаться, особенно если вы используете SQL Server 2014 или более позднюю версию. Если perf важен для расчета медианы, я настоятельно рекомендую попробовать и выполнить тестирование нескольких вариантов, рекомендованных в этой статье, чтобы убедиться, что вы нашли лучший вариант для своей схемы.
Я также был бы особенно осторожен при использовании функции (новая в SQL Server 2012),
PERCENTILE_CONT
которая рекомендована в одном из других ответов на этот вопрос, потому что в статье, приведенной выше, установлено, что эта встроенная функция в 373 раза медленнее, чем самое быстрое решение. Вполне возможно, что это несоответствие улучшилось за последние 7 лет, но лично я бы не использовал эту функцию на большом столе, пока не проверил ее производительность по сравнению с другими решениями.ОРИГИНАЛЬНЫЙ ПОЧТА 2009 НИЖЕ:
Есть много способов сделать это с резко меняющейся производительностью. Вот одно особенно хорошо оптимизированное решение, от Medians, ROW_NUMBERs и производительности . Это особенно оптимальное решение, когда речь идет о фактических операциях ввода-вывода, сгенерированных во время выполнения, - это выглядит дороже, чем другие решения, но на самом деле намного быстрее.
На этой странице также обсуждаются другие решения и детали тестирования производительности. Обратите внимание на использование уникального столбца в качестве устранения неоднозначности в случае, если имеется несколько строк с одинаковым значением медианного столбца.
Как и во всех сценариях производительности базы данных, всегда пытайтесь протестировать решение с реальными данными на реальном оборудовании - вы никогда не знаете, когда изменение в оптимизаторе SQL Server или какая-либо особенность в вашей среде замедлит обычно быстрое решение.
источник
Если вы используете SQL 2005 или выше, это хороший, простой расчет медианы для одного столбца в таблице:
источник
select gid, median(score) from T group by gid
. Вам нужен коррелированный подзапрос для этого?В SQL Server 2012 вы должны использовать PERCENTILE_CONT :
Смотрите также: http://blog.sqlauthority.com/2011/11/20/sql-server-introduction-to-percentile_cont-analytic-functions-introduced-in-sql-server-2012/
источник
DISTINCT
илиGROUPY BY SalesOrderID
? В противном случае у вас будет много повторяющихся строк.PERCENTILE_DISC
Мой оригинальный быстрый ответ был:
Это даст вам средний и межквартильный диапазон одним махом. Если вы действительно хотите только одну строку, которая является медианой, раскомментируйте предложение where.
Когда вы добавляете это в план объяснения, 60% работы заключается в сортировке данных, что неизбежно при расчете зависимой от позиции статистики, подобной этой.
Я исправил ответ, следуя превосходному предложению Роберта Шевчика-Робайза в комментариях ниже:
Это должно вычислить правильные значения медианы и процентили, когда у вас есть четное количество элементов данных. Опять же, раскомментируйте последний пункт where, если вам нужна только медиана, а не все процентили.
источник
Даже лучше:
От самого мастера Ицик Бен-Ган !
источник
MS SQL Server 2012 (и более поздние версии) имеет функцию PERCENTILE_DISC, которая вычисляет определенный процентиль для отсортированных значений. PERCENTILE_DISC (0.5) вычислит медиану - https://msdn.microsoft.com/en-us/library/hh231327.aspx
источник
Простой, быстрый, точный
источник
Если вы хотите использовать функцию «Создать агрегат» в SQL Server, это то, как это сделать. Делая это таким образом, вы получаете возможность писать чистые запросы. Обратите внимание, что этот процесс может быть легко адаптирован для вычисления значения процентиля.
Создайте новый проект Visual Studio и установите целевую платформу на .NET 3.5 (это для SQL 2008, он может отличаться в SQL 2012). Затем создайте файл класса и вставьте следующий код или эквивалент C #:
Затем скомпилируйте его, скопируйте файл DLL и PDB на компьютер с SQL Server и выполните следующую команду в SQL Server:
Затем вы можете написать запрос для вычисления медианы следующим образом: SELECT dbo.Median (Field) FROM Table
источник
Я только что наткнулся на эту страницу, когда искал основанное на множестве решение для медианы. Посмотрев здесь некоторые решения, я пришел к следующему. Надежда это помогает / работает.
источник
Следующий запрос возвращает медиану из списка значений в одном столбце. Его нельзя использовать как или вместе с агрегатной функцией, но вы все равно можете использовать его как подзапрос с предложением WHERE во внутреннем выборе.
SQL Server 2005+:
источник
Хотя решение Джастина Гранта выглядит надежным, я обнаружил, что если в заданном ключе раздела есть несколько повторяющихся значений, номера строк для повторяющихся значений ASC оказываются не по порядку, поэтому они не выровнены должным образом.
Вот фрагмент из моего результата:
Я использовал код Джастина в качестве основы для этого решения. Хотя это и не так эффективно, учитывая использование нескольких производных таблиц, это решает проблему с порядком строк, с которой я столкнулся. Любые улучшения приветствуются, так как я не настолько опытен в T-SQL.
источник
Пример Джастина выше очень хорош. Но этот первичный ключ должен быть изложен очень четко. Я видел этот код в дикой природе без ключа, и результаты плохие.
Жалоба на Percentile_Cont, которую я получаю, заключается в том, что она не даст вам фактического значения из набора данных. Чтобы получить медиану, которая является фактическим значением из набора данных, используйте Percentile_Disc.
источник
В UDF напишите:
источник
Медианный поиск
Это самый простой способ найти медиану атрибута.
источник
Смотрите другие решения для вычисления медианы в SQL здесь: « Простой способ вычисления медианы с MySQL » (решения в основном не зависят от производителя).
источник
Для непрерывной переменной / меры 'col1' из 'table1'
источник
Используя агрегат COUNT, вы можете сначала подсчитать количество строк и сохранить их в переменной с именем @cnt. Затем вы можете вычислить параметры для фильтра OFFSET-FETCH, чтобы указать, основываясь на qty-порядке, сколько строк пропустить (значение смещения) и сколько фильтровать (значение выборки).
Число пропускаемых строк равно (@cnt - 1) / 2. Очевидно, что для нечетного числа это вычисление правильное, потому что сначала вы вычитаете 1 для одного среднего значения, а затем делите на 2.
Это также работает правильно для четного счета, потому что деление, используемое в выражении, является целочисленным делением; поэтому, вычитая 1 из четного числа, вы остаетесь с нечетным значением.
При делении этого нечетного значения на 2 дробная часть результата (.5) усекается. Количество извлекаемых строк - 2 - (@cnt% 2). Идея состоит в том, что когда счет нечетный, результат операции по модулю равен 1, и вам нужно выбрать 1 строку. Когда счет является четным, результат операции по модулю равен 0, и вам нужно выбрать 2 строки. Вычитая 1 или 0 результата операции по модулю из 2, вы получаете желаемые 1 или 2 соответственно. Наконец, чтобы вычислить срединное значение, возьмите одно или два результирующих значения и примените среднее значение после преобразования входного целочисленного значения в числовое значение следующим образом:
источник
Я хотел выработать решение самостоятельно, но мой мозг сломался и упал на пути. Я думаю, что это работает, но не проси меня объяснить это утром. :П
источник
источник
Это работает с SQL 2000:
источник
Для таких новичков, как я, которые изучают самые основы, мне лично легче следовать этому примеру, так как легче понять, что именно происходит и откуда берутся медианные значения ...
В абсолютном страхе от некоторых кодов выше, хотя !!!
источник
Это настолько простой ответ, насколько я мог придумать. Работал хорошо с моими данными. Если вы хотите исключить определенные значения, просто добавьте предложение where к внутреннему выбору.
источник
Следующее решение работает при этих предположениях:
Код:
источник
источник
Я пробую несколько вариантов, но из-за того, что мои записи данных имеют повторяющиеся значения, версии ROW_NUMBER, кажется, не являются выбором для меня. Итак, вот запрос, который я использовал (версия с NTILE):
источник
Опираясь на ответ Джеффа Этвуда, приведенный выше, он использует GROUP BY и соответствующий подзапрос, чтобы получить медиану для каждой группы.
источник
Часто нам может потребоваться рассчитать медиану не только для всей таблицы, но и для агрегатов по некоторому идентификатору. Другими словами, рассчитайте медиану для каждого идентификатора в нашей таблице, где каждый идентификатор имеет много записей. (на основе решения, отредактированного @gdoron: хорошая производительность и работает во многих SQL)
Надеюсь, поможет.
источник
На ваш вопрос Джефф Этвуд уже дал простое и эффективное решение. Но, если вы ищете какой-то альтернативный подход для вычисления медианы, вам поможет код SQL ниже.
Если вы хотите рассчитать медиану в MySQL, эта ссылка на github будет полезна.
источник
Это самое оптимальное решение для поиска медиан, о которых я могу думать. Имена в примере основаны на примере Джастина. Убедитесь, что существует индекс для таблицы Sales.SalesOrderHeader со столбцами индекса CustomerId и TotalDue в этом порядке.
ОБНОВИТЬ
Я был немного не уверен в том, какой метод имеет лучшую производительность, поэтому я провел сравнение между моим методом Джастином Грантом и Джеффом Этвудсом, выполнив запрос на основе всех трех методов в одном пакете, и стоимость пакета каждого запроса составила:
Без индекса:
И с индексом
Я попытался увидеть, насколько хорошо масштабируются запросы, если у вас есть индекс, создавая больше данных из примерно 14 000 строк в 2–512 раз, что в итоге составляет около 7,2 млн. Строк. Обратите внимание, что я удостоверился, что поле CustomeId было уникальным для каждого раза, когда я делал одну копию, чтобы пропорция строк по сравнению с уникальным экземпляром CustomerId оставалась постоянной. Пока я делал это, я запускал исполнения, где впоследствии перестраивал индекс, и заметил, что результаты стабилизировались примерно в 128 раз с данными, которые у меня были к этим значениям:
Мне было интересно, как на производительность могло повлиять масштабирование числа строк, но сохранение уникального константы CustomerId, поэтому я настроил новый тест, в котором я сделал именно это. Теперь вместо стабилизации соотношение стоимости партии продолжало расходиться, также вместо примерно 20 строк на CustomerId в среднем у меня было в итоге около 10000 строк на такой уникальный Id. Числа где:
Я убедился, что реализовал каждый метод правильно, сравнивая результаты. Мой вывод заключается в том, что метод, который я использовал, как правило, быстрее, пока существует индекс. Также заметил, что этот метод является то, что рекомендуется для этой конкретной проблемы в этой статье https://www.microsoftpressstore.com/articles/article.aspx?p=2314819&seqNum=5
Еще одним способом еще более повысить производительность последующих вызовов этого запроса является сохранение информации счетчика во вспомогательной таблице. Вы могли бы даже поддерживать его, имея триггер, который обновляет и хранит информацию о количестве строк SalesOrderHeader, зависящем от CustomerId, и, конечно, вы можете просто сохранить медиану.
источник
Для крупномасштабных наборов данных вы можете попробовать эту GIST:
https://gist.github.com/chrisknoll/1b38761ce8c5016ec5b2
Он работает путем агрегирования различных значений, которые вы найдете в вашем наборе (например, возраст или год рождения и т. Д.), И использует оконные функции SQL, чтобы найти любую процентильную позицию, указанную в запросе.
источник