Пользовательские функции ранжирования/аналитики в SQL Server 2008
-
20-09-2019 - |
Вопрос
Я планирую миграцию хранилища данных на SQL Server 2008 и пытаюсь придумать способы репликации аналитических функций LAG, LEAD, FIRST_VALUE и LAST_VALUE из Oracle в SQL Server 2008.Они не включены в SQL Server 2008, хотя основной механизм оконных аналитических функций (например,ROW_NUMBER, RANK и DENSE_RANK присутствуют).
Для этих функций можно добиться той же функции, создав подзапрос, который присваивает каждой строке номер с помощью ROW_NUMBER, а затем выполняя самообъединения этого запроса для поиска связанных строк с соседними номерами строк (для LAG и LEAD) или номер строки 1 (для FIRST_VALUE).
Я ожидаю, что выполнение самосоединений снизит эффективность операции:но у меня пока нет SQL-сервера, чтобы проверить это.Поэтому, не оценив производительность, мне интересно, есть ли лучший обходной путь, позволяющий избежать самообъединений.
Глядя на документацию по определяемые пользователем агрегатные функции, вполне возможно, что одна и та же структура кода может использоваться для предоставления определяемых пользователем аналитических функций.
Итак, мой вопрос:Можете ли вы добавить предложение OVER() после пользовательской агрегатной функции, чтобы она вызывалась как аналитическая функция?
Если да, то вызывается ли метод Terminate() один раз для каждой строки?Требуется ли что-то особенное, чтобы гарантировать отправку строк в вашу UDF в порядке, указанном в предложении OVER()?
Решение
Я бы использовал самообъединения, а не udfs.
Вы смотрите на скалярную UDFS, использующую доступ к таблицам, который почти всегда дает плохую производительность (это курсор).В противном случае вы, вероятно, могли бы использовать APPLY, но это также выполняется построчно.
Кроме того, функции Oracle не являются агрегатными функциями.Пользовательский агрегат все равно должен будет выполнять ту же обработку над набором результатов.
Помните, что внутри Oracle все равно придется выполнять некоторую построчную обработку, чтобы вычислить значения.
Итак, пример SQL Server 2005+ для FIRST_VALUE (не проверялось) с использованием самостоятельного соединения.
Обратите внимание на перекрестное соединение, которое отделяет FIRST_VALUE от остальных 2, поскольку наборы результатов не имеют никакой связи.Если вы использовали UDF или определяемое пользователем agg, то, скорее всего, вам придется вычислять FIRST_VALUE снова и снова для каждой строки из первого набора результатов.
;WITH CTE AS
(
SELECT
department_id, last_name, salary,
ROW_NUMBER() OVER (ORDER BY salary) AS ranking
FROM employees
WHERE department_id = 90
)
SELECT
c1.department_id, c1.last_name, c1.salary,
c2.last_name as Poorest
FROM
CTE c1
CROSS JOIN
(SELECT last_name FROM CTE WHERE Ranking = 1) c2
ORDER BY
c1.employee_id
Другие советы
В SQL-сервере аналитика является частью SSAS;там вы найдете FirstNonEmpty, LastNonEmpty, FirstChild, LastChild.Он включен в стандартную и корпоративную версии SQL-сервера; глянь сюда.То есть, если вы хотите строить кубики.