W SQL można realizować logikę biznesową za pomocą funkcji zdefiniowanych przez użytkownika (User Defined Functions, UDF), co pozwala przenieść część obliczeń i zasad biznesowych do bazy danych.
Funkcje skalarne zwracają jedną wartość i są wywoływane w wyrażeniach — na przykład, aby obliczyć całkowitą kwotę na podstawie parametrów:
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; -- Przykład użycia: SELECT Name, dbo.GetDiscount(Price, LoyaltyLevel) AS DiscountPrice FROM Products;
Funkcje tabelaryczne zwracają zestaw wierszy (tabelę):
CREATE FUNCTION dbo.ActiveOrders(@userId INT) RETURNS TABLE AS RETURN ( SELECT * FROM Orders WHERE UserId = @userId AND Status = 'Active' ); -- Użycie: SELECT * FROM dbo.ActiveOrders(123);
Różnice, ograniczenia i zalecenia:
Jaka jest różnica pomiędzy funkcją tabelaryczną INLINE a funkcją tabelaryczną wielooperacyjną (multi-statement)? Jak ten wybór wpływa na wydajność?
Odpowiedź i przykład:
-- INLINE CREATE FUNCTION dbo.InlineActiveOrders(@userId INT) RETURNS TABLE AS RETURN ( SELECT * FROM Orders WHERE UserId = @userId AND Status = 'Active' ); -- Funkcja wielooperacyjna CREATE FUNCTION dbo.MultiActiveOrders(@userId INT) RETURNS @result TABLE (...) AS BEGIN INSERT INTO @result SELECT ... -- logika RETURN END
Historia
Projekt: Analiza finansowa.
Używaliśmy skalarnych UDF w części select raportu na dużej masie tabel: SELECT Amount, dbo.CalcTax(Amount, Type) FROM Transactions. Zapytanie trwało 5-10 minut z powodu przetwarzania UDF wierszami. Przepisano na wbudowane CASE: czas został skrócony do sekund.
Historia
Projekt: E-commerce. Do wyszukiwania koszyków użytkowników używaliśmy wielooperacyjnych funkcji tabelarycznych, gdzie była logika filtrowania z kilku etapów. Okazało się, że SQL nie buduje optymalnego planu i wykonuje skanowanie, nawet jeśli potrzebny jest jeden element. Zastąpienie funkcją INLINE od razu przyspieszyło zapytania 50-krotnie.
Historia
Projekt: CRM. Przenieśliśmy logikę biznesową przyznawania bonusów do skomplikowanej UDF. Po kilku miesiącach zrozumieliśmy, że formuły biznesowe się zmieniły, a aktualizacja funkcji jest trudna ze względu na sztywne powiązania z danymi. W iteracyjnym produkcie UDF doprowadziło do dużych wydatków na koordynację zmian między backendem a bazą danych.