SQL Server w logistyce

Funkcja-strażnik: jedna reguła i dla przycisku, i dla zapisu

Funkcja tabelowa inline zwraca pusty tekst albo kod odmowy, a zapytanie przycisku i procedura zapisu pytają tę samą funkcję. Ocena terminu ma pięć stanów, z progiem w miesiącu kalendarzowym.

sql.server.net.pl/sql-server/
Abstrakcyjny panel z tabelą i wykresem słupkowym na tle rozmytych świateł miasta
Abstrakcyjny panel z tabelą i wykresem słupkowym na tle rozmytych świateł miasta
W skrócie
  • Funkcja: zwraca pusty tekst, gdy akcję wykonać można, a w przeciwnym razie krótki kod odmowy.
  • Dwa miejsca: zapytanie przycisku i procedura zapisu pytają tę samą funkcję, więc reguła nie rozjeżdża się w dwóch miejscach.
  • Termin: termin zapisany jako tekst oceniamy w pięciu stanach, z progiem w miesiącu kalendarzowym od dnia oceny.
  • Test: przykłady sprawdziliśmy na poziomach zgodności 130 i 160.

Funkcja tabelowa inline, która zwraca kod odmowy, pozwala zapisać regułę dopuszczalności raz i oprzeć na niej przycisk oraz zapis. Piszemy dla programisty T-SQL, który chce, żeby pytanie „czy można” miało jedno miejsce w kodzie i sterowało jednocześnie dostępnością przycisku oraz procedurą zapisu. Funkcja zwraca pusty tekst, gdy akcję wykonać można, albo niepusty kod odmowy. Zapytanie przycisku i procedura zapisu pytają tę samą funkcję.

Reguła „czy można wykonać akcję” zapisana jako funkcja tabelowa inline zwraca pusty tekst albo kod odmowy, a ta sama funkcja steruje zapytaniem przycisku i procedurą zapisu, więc obejście przycisku nie zmienia danych. Ocena terminu w tej samej konstrukcji ma pięć stanów, a próg liczy się jako miesiąc kalendarzowy od dnia przekazanego jako parametr.

Dlaczego reguła w dwóch miejscach z czasem daje dwa różne wyniki

Reguła „czy można wykonać akcję” pojawia się zwykle w dwóch miejscach: w zapytaniu, które decyduje o dostępności przycisku, i w procedurze, która zapisuje decyzję. Gdy oba miejsca liczą ją osobno, pierwsza zmiana dotyka tylko jednego z nich i wyniki zaczynają się różnić. Przycisk bywa wtedy nieaktywny, choć procedura przyjęłaby zapis, albo aktywny w sytuacji, w której zapis powinien zostać odrzucony.

Wzorzec z tego artykułu usuwa drugą regułę. Jest jedna funkcja, a zapytanie przycisku i procedura zapisu ją wywołują, więc nie ma drugiego kodu, który mógłby odejść od pierwszego. Przykład ma trzy elementy: ocenę terminu zapisanego jako tekst, funkcję-strażnika, która składa z tej oceny kod odmowy, oraz procedurę zapisu decyzji. Ocena terminu i strażnik to dwie osobne funkcje, a nie jeden kod.

Jeśli przycisk i zapis pytają tę samą funkcję, nie ma drugiej reguły, która mogłaby się rozjechać.

Jak ocenić termin zapisany jako tekst i dlaczego daje pięć stanów

Termin w przykładzie jest tekstem wpisywanym ręcznie, więc funkcja oceny przyjmuje parametr tekstowy, a nie datę. Drugi parametr to dzień oceny przekazany przez wywołującego, a nie bieżąca data pobrana z zegara. Poniższy blok tworzy trzy tabele przykładu (zlecenia z terminem, rejestr decyzji i listę loginów uprawnionych do decyzji) oraz funkcję oceny. Wywołanie GO jest separatorem narzędzia, a nie instrukcją T-SQL.

Pięć stanów oceny terminu
Stan (przykład)WarunekSkutek
brakwpis pusty albo NULLbez kontroli
bladwpis nie jest datą albo nie podano dnia ocenyodmowa
minaltermin przed dniem ocenyodmowa
wymaga_zgodytermin nie przed dniem oceny i przed dniem oceny plus miesiącwydanie po zgodzie
oktermin nie przed dniem oceny plus miesiącbez ograniczeń

Pięć stanów zwracanych przez funkcję oceny terminu.

CREATE TABLE dbo.zlecenie_przyklad (id int PRIMARY KEY, termin varchar(30) NULL);
CREATE TABLE dbo.decyzja_przyklad (zlecenie_id int PRIMARY KEY, decyzja char(1) NOT NULL, termin_wpisu date NULL);
CREATE TABLE dbo.przelozony_przyklad (login varchar(30) PRIMARY KEY);
GO
CREATE FUNCTION dbo.ocena_terminu_przyklad (@txt varchar(30), @dzis date)
RETURNS TABLE
AS
RETURN
SELECT x.termin,
       CAST(CASE WHEN x.txt IS NULL THEN 'brak'
                 WHEN x.termin IS NULL THEN 'blad'
                 WHEN @dzis IS NULL THEN 'blad'
                 WHEN x.termin < @dzis THEN 'minal'
                 WHEN x.termin < DATEADD(MONTH, 1, @dzis) THEN 'wymaga_zgody'
                 ELSE 'ok' END AS varchar(15)) AS stan
FROM (SELECT NULLIF(LTRIM(RTRIM(@txt)), '') AS txt,
             TRY_CAST(NULLIF(LTRIM(RTRIM(@txt)), '') AS date) AS termin) AS x;

Trzy tabele przykładu i funkcja oceny terminu.

Wewnętrzne podzapytanie przycina tekst i zamienia pusty tekst na NULL, a potem próbuje zamienić go na datę przez TRY_CAST. Pusty wpis daje stan brak, a wpis niebędący datą daje stan blad. TRY_CAST zwraca NULL zamiast przerywać zapytanie, więc niepoprawny tekst trafia do stanu blad i nie zatrzymuje całej listy zleceń. Stan blad dostaje też wywołanie bez dnia oceny.

Kolejność gałęzi CASE ma znaczenie, bo wygrywa pierwsza spełniona: najpierw brak wpisu, potem wpis niebędący datą albo brak dnia oceny, a dopiero po nich porównania dat. Termin w dniu oceny nie jest jeszcze miniony i wymaga zgody. CAST do varchar(15) nadaje wynikowi jeden typ, więc stany tworzą jedną kolumnę o stałej szerokości. Inną ocenę liczoną w T-SQL opisujemy w artykule o sposobie oceny w T-SQL, a tutaj interesuje nas tylko wykorzystanie oceny przez strażnika.

Jak funkcja tabelowa inline zwraca pusty tekst albo kod odmowy

Funkcja-strażnik składa kod odmowy z oceny terminu i z kilku sprawdzeń pomocniczych. Jest to funkcja tabelowa inline, podobna konstrukcją do tej, którą opisujemy w tekście o funkcji inline zwracającej użytkownika. Zwraca jedną kolumnę z kodem: pusty tekst oznacza, że można, a niepusta wartość jest kodem odmowy.

CREATE FUNCTION dbo.mozna_przyklad (@id int, @decyzja char(1), @login varchar(30), @dzis date)
RETURNS TABLE
AS
RETURN
SELECT CAST(CASE
         WHEN z.id IS NULL OR ISNULL(@decyzja, '') NOT IN ('1', '2') THEN 'brak_wyboru'
         WHEN NOT EXISTS (SELECT 1 FROM dbo.przelozony_przyklad AS p WHERE p.login = @login) THEN 'brak_uprawnien'
         WHEN o.stan IN ('minal', 'blad') THEN 'termin_minal'
         WHEN o.stan IN ('ok', 'brak') THEN 'niepotrzebna'
         WHEN d.decyzja = @decyzja AND d.termin_wpisu = o.termin THEN 'juz_podjeta'
         ELSE '' END AS varchar(20)) AS kod
FROM (SELECT 1 AS x) AS s
LEFT JOIN dbo.zlecenie_przyklad AS z ON z.id = @id
LEFT JOIN dbo.decyzja_przyklad AS d ON d.zlecenie_id = z.id
OUTER APPLY dbo.ocena_terminu_przyklad(z.termin, @dzis) AS o;

Funkcja-strażnik zwracająca pusty tekst albo kod odmowy.

Gałęzie CASE sprawdzają kolejno pięć powodów odmowy.

Pięć kodów odmowy w kolejności sprawdzania
KolejnośćKodZnaczenie
1brak_wyboruzlecenie nie istnieje albo decyzja jest inna niż 1 i 2
2brak_uprawnienlogin nie występuje na liście uprawnionych
3termin_minalstan terminu to minal albo blad
4niepotrzebnastan terminu to ok albo brak, bo zgoda nie jest wtedy potrzebna
5juz_podjetata sama decyzja jest już zapisana dla tego samego terminu

Kody odmowy zwracane przez funkcję-strażnika.

Zapytanie startuje od jednowierszowego zbioru, a lewe złączenia i OUTER APPLY sprawiają, że funkcja zwraca wiersz także wtedy, gdy zlecenia nie ma. Brak zlecenia kończy się więc kodem brak_wyboru, a nie pustym wynikiem. Kod jest tylko krótkim identyfikatorem powodu, a komunikat dla użytkownika powstaje poza funkcją.

Granica wzorca: funkcja decyduje o dopuszczeniu akcji i nie zastępuje blokad. Pusty kod mówi tylko tyle, że w chwili pytania akcję wykonać można.

Jak przycisk i procedura zapisu korzystają z tej samej funkcji

Zapytanie przycisku pyta funkcję i zależnie od wyniku zwraca adres okna decyzji, gdy kod jest pusty, albo adres komunikatu z kodem odmowy. W teście sprowadzamy je do samego kodu, żeby porównać go z wynikiem zapisu. Procedura zapisu woła tę samą funkcję przed zapisem decyzji, a przy niepustym kodzie zwraca wiersz z wynikiem ERR i kodem i nie zmienia danych.

CREATE PROCEDURE dbo.decyzja_przyklad_zapisz @id int, @decyzja char(1), @login varchar(30), @dzis date
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @kod varchar(20) = (SELECT kod FROM dbo.mozna_przyklad(@id, @decyzja, @login, @dzis));
    IF ISNULL(@kod, 'brak_wyboru') <> ''
    BEGIN
        SELECT 'ERR' AS wynik, ISNULL(@kod, 'brak_wyboru') AS kod;
        RETURN;
    END;
    DELETE dbo.decyzja_przyklad WHERE zlecenie_id = @id;
    INSERT dbo.decyzja_przyklad (zlecenie_id, decyzja, termin_wpisu)
    SELECT @id, @decyzja, o.termin
    FROM dbo.zlecenie_przyklad AS z CROSS APPLY dbo.ocena_terminu_przyklad(z.termin, @dzis) AS o
    WHERE z.id = @id;
    SELECT 'OK' AS wynik, '' AS kod;
END;

Procedura zapisu decyzji pytająca funkcję-strażnika.

Pusty kod prowadzi do DELETE i INSERT, które zapisują decyzję razem z terminem, którego dotyczy. Termin zapisany przy decyzji jest później porównywany z terminem bieżącym, więc po jego zmianie decyzja przestaje obowiązywać i wymagana jest nowa. Gdy funkcja nie zwróci wiersza, procedura traktuje to jak brak wyboru. O budowie procedury zapisu piszemy szerzej w tekście o procedurze zapisu w T-SQL.

Jedna funkcja-strażnik pytana z dwóch miejscSchemat: zapytanie przycisku i procedura zapisu pytają tę samą funkcję-strażnika. Wynik to pusty tekst albo kod odmowy, a ocena terminu ma pięć stanów. Jedna reguła pytana z dwóch miejsc Zapytanie przycisku i procedura zapisu wołają tę samą funkcję, więc obejście przycisku nie zmienia danych. Zapytanie przycisku Pyta funkcję i zależnie od wyniku zwraca adres: Kod pusty: adres okna decyzji. Kod odmowy: adres komunikatu z kodem. Funkcja-strażnik: pusty tekst albo kod Pusty tekst: można wykonać akcję. Niepusty tekst: kod odmowy, na przykład termin_minal. SELECT kod FROM dbo.mozna_przyklad(...) Procedura zapisu Woła funkcję przed zmianą danych. Kod pusty: zapis decyzji. Kod niepusty: wiersz z wynikiem ERR i kodem. pyta pyta Ocena terminu (5 stanów) Funkcja wołana przez strażnika. ocena brak bez kontroli blad odmowa minal odmowa wymaga_zgody wydanie po zgodzie ok bez ograniczeń Kod odmowy Komunikat dla użytkownika, brak zmiany danych. Jeśli przycisk i zapis pytają tę samą funkcję, nie ma drugiej reguły, która mogłaby się rozjechać.
Schemat: jedna funkcja-strażnik pytana przez zapytanie przycisku i przez procedurę zapisu; wynik to pusty tekst albo kod odmowy.

Granica wzorca: sprawdzenie funkcją i zapis decyzji to dwa osobne kroki bez transakcji. Przykład nie jest więc odporny na jednoczesne wywołanie z dwóch sesji, w którym obie przejdą sprawdzenie, zanim któraś zapisze decyzję.

Dlaczego miesiąc kalendarzowy ma granicę zależną od dnia

Próg oceny to DATEADD(MONTH, 1, dzień oceny), czyli przesunięcie o miesiąc według kalendarza, a nie o stałą liczbę dni. Zgody wymaga termin, który przypada nie przed dniem oceny i przed progiem, a termin dokładnie miesiąc po dniu oceny zgody już nie wymaga. Termin przypadający dzień przed progiem nadal wymaga zgody.

Granica zależy od dnia oceny. Gdy dzień oceny przypada na 31. dzień miesiąca, a następny miesiąc jest krótszy, DATEADD zwraca ostatni dzień tego krótszego miesiąca. Próg nie jest więc równy trzydziestu dniom, a wzorzec, który dodałby stałą liczbę dni, dałby inną granicę niż kalendarz. Test zawiera oba przypadki: termin dzień przed granicą krótszego miesiąca oraz termin dokładnie w dniu granicy.

SELECT t.opis, t.dzis, t.wejscie, o.stan, t.oczekiwane,
       CASE WHEN o.stan = t.oczekiwane THEN 'OK' ELSE 'BLAD' END AS wynik
FROM (VALUES
    (N'brak (NULL)', CAST('2026-10-12' AS date), CAST(NULL AS varchar(30)), 'brak'),
    (N'pusty tekst', '2026-10-12', '', 'brak'),
    (N'nie jest datą', '2026-10-12', 'abc', 'blad'),
    (N'nieistniejąca data', '2026-10-12', '2026-02-30', 'blad'),
    (N'wczoraj', '2026-10-12', '2026-10-11', 'minal'),
    (N'dziś (dzień terminu)', '2026-10-12', '2026-10-12', 'wymaga_zgody'),
    (N'miesiąc minus dzień', '2026-10-12', '2026-11-11', 'wymaga_zgody'),
    (N'dokładnie miesiąc', '2026-10-12', '2026-11-12', 'ok'),
    (N'za rok', '2026-10-12', '2027-10-12', 'ok'),
    (N'31 stycznia, dzień przed granicą', '2026-01-31', '2026-02-27', 'wymaga_zgody'),
    (N'31 stycznia, granica 28 lutego', '2026-01-31', '2026-02-28', 'ok'),
    (N'brak dnia oceny', NULL, '2026-10-20', 'blad')) AS t(opis, dzis, wejscie, oczekiwane)
CROSS APPLY dbo.ocena_terminu_przyklad(t.wejscie, t.dzis) AS o;

Dwanaście przypadków oceny terminu z oczekiwanym stanem.

Wynik oceny terminu w dwunastu przypadkach
PrzypadekTerminDzień ocenyStanWynik
brak (NULL)NULLpodanybrakOK
pusty tekstpustypodanybrakOK
nie jest datąabcpodanybladOK
nieistniejąca datazapis ISO z nieistniejącym dniem miesiącapodanybladOK
wczorajdzień oceny minus 1 dzieńpodanyminalOK
dzień ocenydzień ocenypodanywymaga_zgodyOK
miesiąc minus dzieńmiesiąc po dniu oceny minus 1 dzieńpodanywymaga_zgodyOK
dokładnie miesiącdokładnie miesiąc po dniu ocenypodanyokOK
za rokrok po dniu ocenypodanyokOK
dzień przed granicą krótszego miesiącadzień przed granicą31. dzień miesiąca, następny krótszywymaga_zgodyOK
granica krótszego miesiącaostatni dzień krótszego miesiąca31. dzień miesiąca, następny krótszyokOK
brak dnia ocenypoprawna dataNULLbladOK

Wynik zapytania oceniającego dwanaście przypadków.

Dwanaście przypadków daje oczekiwany stan na poziomach zgodności 130 i 160, w tym granicę krótszego miesiąca i brak dnia oceny.

Jakie przypadki brzegowe sprawdzić, zanim reguła trafi do użytku

Oprócz oceny terminu sprawdzamy zgodność przycisku i zapisu. Test wstawia pięć zleceń i dodaje szóste, które nie istnieje, a potem pyta funkcję tak jak przycisk i wywołuje procedurę zapisu z tą samą decyzją, tym samym loginem uprawnionego i tym samym dniem oceny. Pytanie przycisku przechodzi przez CROSS APPLY po liście zleceń, więc jedno zapytanie ocenia całą listę. Wynik zapisu trafia do tabeli tymczasowej, a ostatnie zapytanie zestawia oba kody.

INSERT dbo.zlecenie_przyklad (id, termin) VALUES (1, '2026-10-11'), (2, '2026-10-20'), (3, '2026-12-01'), (4, 'abc'), (5, NULL);
INSERT dbo.przelozony_przyklad (login) VALUES ('przelozony1');
DECLARE @dzis date = '2026-10-12';
SELECT z.id, m.kod AS kod_przycisku INTO #przycisk
FROM (SELECT id FROM dbo.zlecenie_przyklad UNION ALL SELECT 6) AS z
CROSS APPLY dbo.mozna_przyklad(z.id, '1', 'przelozony1', @dzis) AS m;
CREATE TABLE #zapis (id int, wynik varchar(3), kod varchar(20));
DECLARE @id int = 1;
WHILE @id <= 6
BEGIN
    INSERT #zapis (wynik, kod) EXEC dbo.decyzja_przyklad_zapisz @id, '1', 'przelozony1', @dzis;
    UPDATE #zapis SET id = @id WHERE id IS NULL;
    SET @id += 1;
END;
SELECT p.id, p.kod_przycisku, s.wynik, s.kod AS kod_zapisu,
       CASE WHEN p.kod_przycisku = s.kod THEN 'zgodne' ELSE 'ROZNE' END AS zgodnosc
FROM #przycisk AS p JOIN #zapis AS s ON s.id = p.id ORDER BY p.id;

Test zgodności: kod dla przycisku i wynik zapisu dla sześciu zleceń.

Zgodność kodu dla przycisku i wyniku zapisu dla sześciu zleceń
Zlecenie (termin)Kod dla przyciskuWynik zapisuKod zapisuZgodność
1 (dzień oceny minus 1 dzień)termin_minalERRtermin_minalzgodne
2 (dzień oceny plus 8 dni)pustyOKpustyzgodne
3 (ponad miesiąc po dniu oceny)niepotrzebnaERRniepotrzebnazgodne
4 (tekst abc)termin_minalERRtermin_minalzgodne
5 (brak terminu)niepotrzebnaERRniepotrzebnazgodne
6 (zlecenie nie istnieje)brak_wyboruERRbrak_wyboruzgodne

Wynik testu zgodności przycisku i zapisu.

Przycisk i zapis dają ten sam kod dla każdego z sześciu zleceń przykładowych. Zlecenie 2 ma termin dzień oceny plus 8 dni, czyli krótszy niż miesiąc, więc strażnik dla loginu z listy zwraca pusty kod, a procedura zapisuje decyzję. Dla loginu spoza listy ta sama funkcja zwraca brak_uprawnien, i to samo dostaje procedura wywołana bez przycisku.

SELECT 'po decyzji' AS moment, kod FROM dbo.mozna_przyklad(2, '1', 'przelozony1', '2026-10-12')
UNION ALL
SELECT 'inny login', kod FROM dbo.mozna_przyklad(2, '1', 'ktos_obcy', '2026-10-12');
UPDATE dbo.zlecenie_przyklad SET termin = '2026-10-25' WHERE id = 2;
SELECT 'po zmianie terminu' AS moment, kod FROM dbo.mozna_przyklad(2, '1', 'przelozony1', '2026-10-12');

Strażnik po zapisaniu decyzji, dla innego loginu i po zmianie terminu.

Kod strażnika po zapisaniu decyzji
MomentKod
po decyzji (ten sam termin)juz_podjeta
inny loginbrak_uprawnien
po zmianie terminu na dzień oceny plus 13 dnipusty (decyzja przestała obowiązywać)

Wynik trzech zapytań po zapisaniu decyzji.

Po zapisaniu decyzji strażnik zwraca juz_podjeta. Gdy termin w zleceniu zmieni się na dzień oceny plus 13 dni, decyzja traci ważność i wraca pusty kod, bo rejestr pamięta termin, którego decyzja dotyczyła.

Ostatni przypadek dotyczy formatu daty, bo konwersja tekstu z kropkami zależy od ustawienia sesji. TRY_CAST na tekście z kropkami daje przy ustawieniu DATEFORMAT dmy datę, w której pierwszy człon jest dniem, a przy mdy datę, w której pierwszy człon jest miesiącem. Zapis ISO daje w obu ustawieniach tę samą datę.

SET DATEFORMAT dmy;
SELECT 'dmy' AS ustawienie, TRY_CAST('12.10.2026' AS date) AS z_kropkami, TRY_CAST('2026-10-12' AS date) AS iso;
SET DATEFORMAT mdy;
SELECT 'mdy' AS ustawienie, TRY_CAST('12.10.2026' AS date) AS z_kropkami, TRY_CAST('2026-10-12' AS date) AS iso;

Ta sama konwersja przy dwóch ustawieniach formatu daty.

Konwersja tekstu na datę przy dwóch ustawieniach DATEFORMAT
UstawienieZapis z kropkamiZapis ISO
DATEFORMAT dmypierwszy człon czytany jako dzieńta sama data
DATEFORMAT mdypierwszy człon czytany jako miesiąc, więc inna datata sama data

Wynik konwersji przy dwóch ustawieniach formatu daty.

Granica wzorca: ocena terminu rozpoznaje datę zgodnie z ustawieniem sesji, więc zapis z kropkami daje różne daty przy różnych ustawieniach formatu. Gdy pole jest tekstem, zapis ISO ma stałe znaczenie, a zapis z kropkami zależy od sesji; funkcja nie próbuje rozpoznać dowolnego formatu, a tekst, który nie jest datą w danym ustawieniu, daje stan blad. Walidację dat w procedurze omawiamy osobno w artykule o walidacji dat w procedurze.

Makieta wyników oceny terminu i funkcji-strażnikaMakieta poglądowa, dane przykładowe: cztery siatki wyników, czyli ocena terminu w dwunastu przypadkach, strażnik po zapisaniu decyzji, konwersja daty zależna od formatu sesji i zgodność przycisku z zapisem dla sześciu zleceń. Wynik zapytania: ocena terminu i kod odmowy Poziomy zgodności 130 i 160 Dzień oceny przekazuje wywołujący; w dwóch przypadkach brzegowych jest to 31. dzień miesiąca przed krótszym miesiącem. SELECT 'po decyzji' AS moment, kod FROM dbo.mozna_przyklad(...) CROSS APPLY dbo.ocena_terminu_przyklad(t.wejscie, t.dzis) AS o; Ocena terminu w dwunastu przypadkach Przypadek Termin Dzień oceny Stan Wynik brak (NULL) NULL podany brak OK pusty tekst pusty podany brak OK nie jest datą abc podany blad OK nieistniejąca data zapis ISO z nieistniejącym dniem miesiąca podany blad OK wczoraj dzień oceny minus 1 dzień podany minal OK dzień oceny dzień oceny podany wymaga_zgody OK miesiąc minus dzień miesiąc po dniu oceny minus 1 dzień podany wymaga_zgody OK dokładnie miesiąc dokładnie miesiąc po dniu oceny podany ok OK za rok rok po dniu oceny podany ok OK dzień przed granicą krótszego miesiąca dzień przed granicą 31. dzień miesiąca, następny krótszy wymaga_zgody OK granica krótszego miesiąca ostatni dzień krótszego miesiąca 31. dzień miesiąca, następny krótszy ok OK brak dnia oceny poprawna data NULL blad OK Strażnik po zapisaniu decyzji dla zlecenia 2 Moment Kod po decyzji (ten sam termin) juz_podjeta inny login brak_uprawnien po zmianie terminu na dzień oceny plus 13 dni pusty (decyzja przestała obowiązywać) Konwersja daty a format sesji Ustawienie Zapis z kropkami Zapis ISO DATEFORMAT dmy pierwszy człon czytany jako dzień ta sama data DATEFORMAT mdy pierwszy człon czytany jako miesiąc, więc inna data ta sama data Dla zapisu z kropkami wynik zależy od formatu daty sesji; zapis ISO daje tę samą datę w obu ustawieniach. Przycisk i zapis dla tej samej decyzji "1", tego samego loginu uprawnionego i tego samego dnia oceny Zlecenie (termin) Kod dla przycisku Wynik zapisu Kod zapisu Zgodność 1 (dzień oceny minus 1 dzień) termin_minal ERR termin_minal zgodne 2 (dzień oceny plus 8 dni) pusty OK pusty zgodne 3 (ponad miesiąc po dniu oceny) niepotrzebna ERR niepotrzebna zgodne 4 (tekst abc) termin_minal ERR termin_minal zgodne 5 (brak terminu) niepotrzebna ERR niepotrzebna zgodne 6 (zlecenie nie istnieje) brak_wyboru ERR brak_wyboru zgodne Makieta poglądowa, dane przykładowe
Makieta poglądowa, dane przykładowe. Cztery siatki wyników opisane w tekście: ocena terminu, strażnik po decyzji, konwersja daty i zgodność przycisku z zapisem.

Pytania do analizy

Przed zastosowaniem wzorca odpowiedz na cztery pytania.

  1. Miejsca reguły: Ile miejsc w Twoim systemie sprawdza tę samą regułę dopuszczalności osobno i czy zmiana reguły dociera do nich jednocześnie?
  2. Kod odmowy: Czy odmowa ma kod, który da się przełożyć na komunikat, czy tylko wartość logiczną bez powodu?
  3. Format daty: W jakim formacie użytkownicy wpisują datę, jeśli pole jest tekstem, i co robi konwersja przy ustawieniu formatu inaczej, niż oczekujesz?
  4. Unieważnianie decyzji: Które dane powinny unieważniać poprzednią decyzję i czy rejestr decyzji pamięta, czego decyzja dotyczyła?
FAQ

Najczęstsze pytania o funkcję-strażnika

01

Dlaczego funkcja tabelowa inline, a nie skalarna?

Funkcja inline jest rozwijana do zapytania i można ją łączyć przez APPLY z listą wierszy, więc ta sama reguła ocenia dostępność przycisku dla całej listy wierszy jednym zapytaniem.

02

Co zwraca funkcja, gdy można wykonać akcję?

Pusty tekst; niepusta wartość to kod odmowy, który zostaje zamieniony na komunikat poza funkcją.

03

Czy samo zapytanie przycisku wystarcza?

Nie; procedura zapisu woła tę samą funkcję przed zapisem danych, więc obejście przycisku nie zmienia stanu.

04

Dlaczego data jest parametrem funkcji oceny?

Dla powtarzalnych testów: dzień oceny przekazuje wywołujący, więc wynik nie zależy od zegara, a bieżącą datę można też policzyć wewnątrz funkcji przez CAST(GETDATE() AS date).

05

Jak działa miesiąc kalendarzowy?

Próg to DATEADD(MONTH, 1, dzień oceny); dla dnia oceny przypadającego na 31. dzień miesiąca przed krótszym miesiącem granica wypada w ostatnim dniu tego krótszego miesiąca, więc bywa inna niż trzydzieści dni.

Słownik pojęć

Słownik pojęć

Pojęcia z zapytań i przykładu opisanych w artykule.

FFunkcja-strażnik
Funkcja zwracająca pusty tekst albo kod odmowy dla danej akcji.
FFunkcja tabelowa inline
Funkcja zwracająca tabelę jednym zapytaniem, rozwijana w miejscu użycia.
KKod odmowy
Krótki identyfikator powodu, zamieniany na komunikat poza funkcją.
MMiesiąc kalendarzowy
Przesunięcie daty o jeden miesiąc według kalendarza, a nie o stałą liczbę dni.
TTRY_CAST
Konwersja, która zamiast błędu zwraca NULL, gdy tekst nie jest wartością danego typu.
RRejestr decyzji
Tabela pamiętająca decyzję razem z danymi, których dotyczyła.

Zobacz to w praktyce

Sprawdź, jak systemy SoftwareStudio oparte na MS SQL Server wspierają ten obszar Twojej firmy.