W większości realizacji SQL (np. T-SQL, PL/pgSQL, PL/SQL) dostępne są konstrukcje sterujące: warunki (IF/CASE), pętle (WHILE/FOR/LOOP), konstrukcje do obsługi błędów. Są one wygodne do automatyzacji logiki biznesowej na serwerze — na przykład do tworzenia złożonych raportów, walidacji reguł biznesowych, orkiestracji procesów ETL i automatyzacji reakcji na zdarzenia.
Jednak nadmierne wykorzystanie pętli i złożonych warunków w procedurach SQL może prowadzić do pogorszenia czytelności i wydajności (przekształcając SQL w "imperatywny chaos" — efekt procedural hell).
Zaleca się używać tych konstrukcji tylko dla operacji, które nie mogą być zrealizowane środkami przetwarzania zestawowego (set-based): na przykład przetwarzania pojedynczego rekordu z dynamiczną logiką.
CREATE PROCEDURE ProcessOrders AS BEGIN DECLARE @OrderID INT, @Total FLOAT DECLARE OrderCursor CURSOR FOR SELECT OrderID FROM Orders WHERE Status = 'NEW' OPEN OrderCursor FETCH NEXT FROM OrderCursor INTO @OrderID WHILE @@FETCH_STATUS = 0 BEGIN SELECT @Total = SUM(Price) FROM OrderItems WHERE OrderID = @OrderID IF @Total > 10000 UPDATE Orders SET Status='MANUAL_CHECK' WHERE OrderID=@OrderID ELSE UPDATE Orders SET Status='APPROVED' WHERE OrderID=@OrderID FETCH NEXT FROM OrderCursor INTO @OrderID END CLOSE OrderCursor DEALLOCATE OrderCursor END
Czy CASE w SELECT zastępuje zagnieżdżone IF-conditions w procedurach i czy mogą być one zamienne?
Odpowiedź: Nie. CASE można stosować tylko w wyrażeniach SELECT/UPDATE/INSERT — dla pól obliczanych. IF — tylko w blokach sterujących procedur/function/triggers i nie można go stosować w "czystym" SELECT.
Przykład:
SELECT CASE WHEN score > 80 THEN 'High' ELSE 'Low' END AS Level FROM students -- IF tutaj jest niemożliwe
Historia
Zespół próbował przepisać cały proces biznesowy z kodu do procedur SQL z obfitością zagnieżdżonych IF/ELSE i pętli. Efekt — zawiły, nieuleczalny kod, wsparcie prawie niemożliwe. Przeszli do przeniesienia logiki z powrotem do aplikacji, pozostawiając jedynie krytyczne procedury.
Historia
W PL/pgSQL z powodu niewłaściwego użycia LOOP bez poprawnego wyjścia (EXIT) w procedurze składowanej powstała "nieskończona" pętla, blokując połączenie z Bazy Danych. Rozwiązano przez wprowadzenie limitu powtórzeń pętli oraz poprawnych warunków wyjścia.
Historia
Błąd w logice zagnieżdżonego IF w procedurze przetwarzania zamówień: brakowało konstrukcji ELSE. Niektóre zamówienia pozostały w niepoprawnym statusie (NULL), czego brakowało w późniejszej walidacji. Dodano domyślną ELSE z wyraźnym zachowaniem domyślnym.