Nowoczesne systemy BI i CRM często wymagają wprowadzenia filtrów użytkownika: ważne jest elastyczne łączenie różnych warunków (według daty, płci, statusu, tagów), a także prawidłowe przecięcie i łączenie ich w języku SQL. Otrzymany kod powinien być czytelny, łatwy do zmiany i dawać oczekiwany rezultat.
Często programiści "na bieżąco" formują WHERE z wieloma AND/OR na podstawie filtrów użytkownika, co prowadzi do błędów logicznych i złożonych do utrzymania zapytań. Problem się zaostrza, jeśli wartości filtrów mogą być nieobecne lub łączone z IN/EXISTS/LIKE.
Dla dynamicznych filtrów wygodnym wzorcem jest "warunek z OR zawsze TRUE, jeśli wartość nie jest zadana":
SELECT * FROM users WHERE (status = @status OR @status IS NULL) AND (gender = @gender OR @gender IS NULL) AND (created >= @from_date OR @from_date IS NULL) AND (city IN (@cities) OR @cities IS NULL);
Lub z pomocą dynamicznego SQL:
DECLARE @sql NVARCHAR(MAX) = N'SELECT * FROM users WHERE 1=1'; IF @status IS NOT NULL SET @sql += N' AND status = @status'; IF @gender IS NOT NULL SET @sql += N' AND gender = @gender'; -- ... EXEC sp_executesql @sql, N'@status NVARCHAR(10),@gender NVARCHAR(10)', @status, @gender;
Kluczowe cechy:
Czy można używać WHERE 1=1 wszędzie zamiast sprawdzania istnienia warunków?
Nie, 1=1 to tylko początkowy warunek do konkatenacji WHERE — nie zastępuje filtrów, a jest używane wyłącznie dla wygody generowania zapytań.
Jakie problemy mogą się pojawić, jeśli IN () trafi pusta lista?
IN (NULL) lub IN () zawsze zwraca false i daje pusty zestaw, nawet przy braku filtra. Dla poprawnej pracy należy osobno sprawdzić, czy lista jest pusta i nie włączać warunku w ogóle.
Jak podobne konstrukcje wpłyną na wykorzystanie indeksów i wydajność?
Jeśli filtry są realizowane z OR lub sprawdzeniami NULL, wiele DBMS przestanie efektywnie używać indeksów, lub zostanie wykonane skanowanie całej tabeli. Należy stosować podejścia z dynamicznym SQL lub filtrami przy użyciu zapytań parametryzowanych, aby planista mógł wybrać indeks.
Klasyczny raport z 10 filtrami, kod formuje WHERE z wieloma OR — przy braku kilku filtrów w wyniku zwracany jest pusty zestaw lub zbyt duże skanowanie, obciążenie serwera wzrasta wielokrotnie.
Zalety:
Oddzielna funkcja formuje filtry tylko dla zadanych parametrów, a dla każdej grupy warunków włącza się oddzielny JOIN/FILTER. Where nie zawiera OR i zbędnych sprawdzeń na NULL.
Zalety: