Muszę napisać procedurę składowaną T-SQL, która aktualizuje wiersz w tabeli. Jeśli wiersz nie istnieje, wstaw go. Wszystkie te kroki są zawinięte przez transakcję.
Dotyczy to systemu rezerwacji, więc musi być atomowy i niezawodny . Zwraca wartość true, jeśli transakcja została popełniona, a lot zarezerwowany.
Jestem nowym użytkownikiem T-SQL i nie jestem pewien, jak go używać @@rowcount
. Tak pisałem do tej pory. Czy jestem na właściwej drodze? Jestem pewien, że to dla ciebie łatwy problem.
-- BEGIN TRANSACTION (HOW TO DO?)
UPDATE Bookings
SET TicketsBooked = TicketsBooked + @TicketsToBook
WHERE FlightId = @Id AND TicketsMax < (TicketsBooked + @TicketsToBook)
-- Here I need to insert only if the row doesn't exists.
-- If the row exists but the condition TicketsMax is violated, I must not insert
-- the row and return FALSE
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO Bookings ... (omitted)
END
-- END TRANSACTION (HOW TO DO?)
-- Return TRUE (How to do?)
sql
sql-server
sql-server-2008
tsql
Whymarrh
źródło
źródło
Odpowiedzi:
Spójrz na polecenie MERGE . Można to zrobić
UPDATE
,INSERT
iDELETE
w jednym sprawozdaniu.Oto działająca implementacja używania
MERGE
- Sprawdza, czy lot jest pełny przed wykonaniem aktualizacji, w przeciwnym razie wstawia.
I wtedy ...
źródło
Zakładam jeden rząd dla każdego lotu? W takim razie:
Zakładam to, co powiedziałem, ponieważ twój sposób robienia rzeczy może przepełnić rezerwację lotu, ponieważ wstawi nowy wiersz, gdy będzie maksymalnie 10 biletów, a ty rezerwujesz 20.
źródło
BEGIN TRAN ... COMMIT
domyślnym poziomie izolacji nie rozwiąże problemu. PO określił, że atomowe i niezawodne są wymaganiami. Twoja odpowiedź nie rozwiązuje tego w żadnej formie ani formie.IF EXISTS (SELECT * FROM Bookings (UPDLOCK, HOLDLOCK) WHERE FLightID = @Id)
?Przekaż updlock, rowlock, wskazówki blokady podczas testowania istnienia rzędu.
Wskazówka dotycząca aktualizacji zmusza zapytanie do zablokowania aktualizacji w wierszu, jeśli już istnieje, uniemożliwiając modyfikowanie go przez inne transakcje do momentu zatwierdzenia lub wycofania.
Wskazówka blokowania zmusza zapytanie do zablokowania zakresu, zapobiegając dodawaniu przez inne transakcje wiersza zgodnego z kryteriami filtrowania do momentu zatwierdzenia lub wycofania.
Wskazówka rowlock wymusza blokowanie ziarnistości do poziomu wiersza zamiast domyślnego poziomu strony, więc twoja transakcja nie blokuje innych transakcji próbujących zaktualizować niepowiązane wiersze na tej samej stronie (ale pamiętaj o kompromisie między zmniejszoną rywalizacją a wzrostem liczby blokowanie narzutów - należy unikać przyjmowania dużej liczby blokad na poziomie wiersza w jednej transakcji).
Więcej informacji można znaleźć na stronie http://msdn.microsoft.com/en-us/library/ms187373.aspx .
Zwróć uwagę, że blokady są pobierane, gdy wykonywane są instrukcje, które je pobierają - wywoływanie begin tran nie daje odporności na kolejną transakcję szczypania blokad na czymś, zanim dojdziesz do tego. Powinieneś spróbować uwzględnić czynnik SQL w celu utrzymywania blokad przez możliwie najkrótszy czas, zatwierdzając transakcję tak szybko, jak to możliwe (pozyskaj późno, zwolnij wcześniej).
Zauważ, że blokady na poziomie wierszy mogą być mniej skuteczne, jeśli twoja PK jest bigintem, ponieważ wewnętrzne haszowanie w SQL Server jest zdegenerowane dla wartości 64-bitowych (różne wartości kluczy mogą mieć skrót do tego samego identyfikatora blokady).
źródło
exists
sprawdzanie bez wskazówek blokujących.piszę moje rozwiązanie. moja metoda nie oznacza „jeśli” ani „scal”. moja metoda jest łatwa.
Na przykład:
Wyjaśnienie:
(1) WYBIERZ col1, col2 FROM TableName GDZIE col1 = @ par1 AND col2 = @ par2 Wybiera z przeszukiwanych wartości TableName
(2) WYBIERZ @ par1, @ par2 GDZIE NIE ISTNIEJE Pobiera, jeśli nie istnieje z (1) podzapytania
(3) Wstawia do wartości kroku TableName (2)
źródło
W końcu udało mi się wstawić wiersz, pod warunkiem, że jeszcze nie istniał, używając następującego modelu:
które znalazłem na:
http://www.postgresql.org/message-id/[email protected]
źródło
To właśnie niedawno musiałem zrobić:
źródło
Aby to osiągnąć, możesz użyć funkcji scalania . W przeciwnym razie możesz zrobić:
źródło
Pełne rozwiązanie znajduje się poniżej (w tym struktura kursora). Ogromne podziękowania dla Cassiusa Porcusa za
begin trans ... commit
kod zamieszczony powyżej.źródło
źródło
źródło
Najlepszym podejściem do tego problemu jest najpierw uczynienie kolumny bazy danych UNIQUE
ALTER TABLE table_name ADD UNIQUE KEY
THEN INSERT IGNORE INTO table_name
, wartość nie zostanie wstawiona, jeśli spowoduje zduplikowanie klucza / już istnieje w tabeli.źródło