В SQL можно реализовывать бизнес-логику через пользовательские функции (User Defined Functions, UDF), что позволяет переносить часть вычислений и бизнес-правил в базу данных.
Скалярные функции возвращают единственное значение и вызываются в выражениях — например, чтобы вычислить итог на основе параметров:
CREATE FUNCTION dbo.GetDiscount(@price DECIMAL(10,2), @loyaltyLevel INT) RETURNS DECIMAL(10,2) AS BEGIN RETURN @price * CASE WHEN @loyaltyLevel = 1 THEN 0.95 WHEN @loyaltyLevel = 2 THEN 0.90 ELSE 1.0 END END; -- Пример использования: SELECT Name, dbo.GetDiscount(Price, LoyaltyLevel) AS DiscountPrice FROM Products;
Табличные функции возвращают набор строк (таблицу):
CREATE FUNCTION dbo.ActiveOrders(@userId INT) RETURNS TABLE AS RETURN ( SELECT * FROM Orders WHERE UserId = @userId AND Status = 'Active' ); -- Использование: SELECT * FROM dbo.ActiveOrders(123);
Отличия, ограничения и рекомендации:
В чем разница между INLINE табличной функцией и многооператорной (multi-statement) табличной функцией? Как влияет этот выбор на производительность?
Ответ и пример:
-- INLINE CREATE FUNCTION dbo.InlineActiveOrders(@userId INT) RETURNS TABLE AS RETURN ( SELECT * FROM Orders WHERE UserId = @userId AND Status = 'Active' ); -- Многооператорная CREATE FUNCTION dbo.MultiActiveOrders(@userId INT) RETURNS @result TABLE (...) AS BEGIN INSERT INTO @result SELECT ... -- логика RETURN END
История
Проект: Финансовая аналитика.
Использовали скалярные UDF в select-части отчётного запроса к большому массиву таблиц: SELECT Amount, dbo.CalcTax(Amount, Type) FROM Transactions. Запрос выполнялся 5-10 минут из-за построчной обработки UDF. Переписали на встроенный CASE: время снизилось до секунд.
История
Проект: E-commerce. Для поиска корзин пользователей использовали многооператорные табличные функции, где была логика фильтрации из нескольких этапов. Оказалось, что SQL не строит оптимальный план и делает сканирование, даже если нужен один элемент. Замена на INLINE-функцию сразу ускорила запросы в 50 раз.
История
Проект: CRM. Вынесли бизнес-логику начисления бонусов в сложную UDF. Через пару месяцев поняли, что формулы бизнеса изменились, а обновить функцию сложно из-за жесткой связки с данными. В итеративном продукте UDF привела к высоким затратам на координaцию изменений между бэкендом и БД.