Sprawdzanie atrybutu w bazie danbych

Witam.

Stworzyłem bazę danych sklepu. Póki co mam tam takie tabele jak Produkty, Klienci, Kategorie, Transakcje. Tabela Produkty zawiera między innymi atrybut Ilosc - czyli ilość dostepnych sztuk danego produktu. Tabela Transakcje również zawiera atrybut Ilosc, który mówi ile sztuk produktu zostało kupionych. I tu pojawia się problem. Otóż chciałbym aby przy próbie dodania rekordu do tabeli Transakcje po dodaniu rekordu nastąpiło sprawdzenie czy w tabeli Produkty jest dostępna odpowiednia ilość danego towaru. Czy takie coś ma sens i jak to napisać?

Poczytaj o wyzwalaczach.

Czytałem o wyzwalaczach, a nawet pisałem proste wyzwalacze :slight_smile:

No właśnie nie wiem jak napisać taki wyzwalacz. Myślę że trzeba by było stworzyć wyzwalacz w Tabeli Transakcje gdzie:

  • trzeba by było jakoś pobrać ID Produktu z tabeli Produkty, który został wstawiony do tabeli Transakcje i na jego podstawie sprawdzić dostępną ilość, (z tym mam problem)

  • później porównać czy jest odpowiednia ilość produktu.

Czy kolumna Ilosc w tabeli Produkt ma być aktualizowana po każdej transakcji? W sensie w tabeli Produkt kolumna Ilosc wynosi 100. Miało miejsce zamówienie na 60 sztuk produktu. W związku z tym po realizacji zamówienia kolumna Ilosc w tabeli Produkt przechowuje wartość 40.

Dobra wygląda na to że działa :slight_smile: Oto co napisałem:

CREATE TRIGGER CheckAv ON Transakcje

AFTER INSERT

AS

	BEGIN

		DECLARE @value INT

		DECLARE @value2 INT

		DECLARE @value3 INT

		SET @value = (SELECT Ilosc FROM inserted)

		SET @value2 = (SELECT P_ID FROM inserted)

		SELECT @value3 = Ilosc FROM Produkty

		WHERE P_ID = @value2 

		IF (@value > @value3 AND @value3 > 0)

		BEGIN

			PRINT 'Zbyt malo produktow'

			ROLLBACK TRANSACTION

		END

		ELSE

		BEGIN

			UPDATE Produkty

			SET Ilosc = Ilosc - @value

			WHERE P_ID = @value2

		END

	END

Czy powinna to zależy tylko i wyłącznie od Ciebie, dlatego pytałem. Może np. gdzieś potrzebujesz informacje o tym jaka była początkowa ilość produktu.

Jeśli chodzi o Twój problem to ja bym tutaj raczej napisał procedurę, która zwraca dwie zmienne. Pierwsza to ID nowowstawionego rekordu, a druga to zmienna zwracająca wartość true/false w zależności od tego, czy Insert się powiódł, czy też nie. Ewentualnie zamiast tej zmiennej procedura mogłaby zwracać ID równe np. -1 (jeśli Insert się nie powiódł).

Procedura ta wykonywałaby trzy instrukcje w obrębie jednej transakcji. Pierwsza instrukcja to byłby Select, który pobrałby ilość produktu jaka pozostanie w tabeli Produkt po wykonaniu instrukcji Insert. Jeśli ta ilość będzie mniejsza od 0 to Insert i Update nie zostanie wykonany. Jeśli ta ilość będzie większa od 0, to najpierw zostanie wykonany insert do tabeli Transakcje, a następnie zostanie wykonany Update tabeli Produkt. I tu jeszcze raz podkreślam wszystko musi iść w obrębie jednej transakcji. Jeśli transakcja się nie powiedzie (w obojętnie którym kroku) to robisz rollback transakcji i zwracasz -1. A jak się powiedzie to zwracasz ID nowowstawionego rekordu. Mógłbyś też np. sobie zwracać jeszcze ilość produktów jaka pozostała w tabeli Produkt.

Jeśli jednak chcesz to mieć na triggerach, to wydaje mi się, że będziesz musiał napisać dwa triggery dla tabeli Transakcje. Pierwszy to będzie Before Insert, który sprawdzi, czy możliwe będzie wykonanie Insert-a (w sensie, czy ilość produktów w tabeli Produkt na to pozwoli). A następny trigger to powinien być After Insert, który wykona Update tabeli Produkt. Choć nie wiem, czy to rozwiązanie zadziała, musiałbym sprawdzić, ale generalnie robiłbym coś w ten deseń.

EDIT: Zauważyłem, że wstawiłeś kod, gdy pisałem posta. Dodam tylko, że w tym kodzie, który wstawiłeś nawet jeśli nie powiedzie się Update tabeli Produkt, to nowy rekord pozostanie w tabeli Transakcje .