SQL, jak zwiększyć lub zmniejszyć jedną dla kolumny int w jednym poleceniu


119

Mam tabelę Zamówienia, która zawiera kolumnę Ilość. Podczas zameldowania lub wymeldowania musimy zaktualizować tę kolumnę Ilość o jeden. Czy jest sposób, aby to zrobić w jednej akcji, czy też musimy pobrać istniejącą wartość, a następnie dodać lub odjąć jedną na wierzchu?

Innym pytaniem jest, kiedy wstawiamy nowy wiersz, czy musimy sprawdzić, czy istnieją te same dane, a następnie wstawić, jeśli nie, co jest dwoma krokami, czy jest lepszy sposób na zrobienie tego?

dzięki,

Odpowiedzi:


250

Aby odpowiedzieć na pierwsze:

UPDATE Orders SET Quantity = Quantity + 1 WHERE ...

Aby odpowiedzieć na drugie:

Można to zrobić na kilka sposobów. Ponieważ nie podałeś bazy danych, założę MySQL.

  1. INSERT INTO table SET x=1, y=2 ON DUPLICATE KEY UPDATE x=x+1, y=y+2
  2. REPLACE INTO table SET x=1, y=2

Oboje poradzą sobie z twoim pytaniem. Jednak pierwsza składnia zapewnia większą elastyczność w aktualizowaniu rekordu, zamiast po prostu go zastępować (tak jak robi to druga).

Pamiętaj, że aby oba istniały, musi być zdefiniowany UNIKATOWY klucz ...


32
Ponieważ nie określiłeś bazy danych, naprawdę powinieneś założyć standardowy SQL.
paxdiablo

12

Pojedynczą odpowiedzią na pierwsze pytanie jest użycie czegoś takiego:

update TBL set CLM = CLM + 1 where key = 'KEY'

Jest to w dużej mierze sposób na wykonanie jednej instrukcji.

Jeśli chodzi o drugie pytanie, nie powinieneś uciekać się do gimnastyki SQL specyficznej dla DBMS (np. UPSERT), Aby uzyskać pożądany wynik. Istnieje standardowa metoda wykonywania aktualizacji lub wstawiania, która nie wymaga określonego systemu DBMS.

try:
    insert into TBL (key,val) values ('xyz',0)
catch:
    do nothing
update TBL set val = val + 1 where key = 'xyz'

Oznacza to, że najpierw próbujesz stworzyć kreację. Jeśli już tam jest, zignoruj ​​błąd. W przeciwnym razie tworzysz go z wartością 0.

Następnie wykonaj aktualizację, która będzie działać poprawnie, niezależnie od tego, czy:

  • wiersz pierwotnie istniał.
  • ktoś zaktualizował go między wstawką a aktualizacją.

To nie jest pojedyncza instrukcja, a jednak, co zaskakujące, tak robimy to z sukcesem przez długi czas.


4

Jeśli rozumiem, aktualizacje powinny być dość proste. Zrobiłbym tylko co następuje.

UPDATE TABLE SET QUANTITY = QUANTITY + 1 and
UPDATE TABLE SET QUANTITY = QUANTITY - 1 where QUANTITY > 0

Aby zaktualizować jeden wiersz zamiast wszystkich wierszy, możesz potrzebować dodatkowych filtrów.

W przypadku wstawiania możesz buforować lokalnie unikalne identyfikatory związane z Twoim rekordem i sprawdzać je w tej pamięci podręcznej i decydować, czy wstawić, czy nie. Alternatywnym podejściem jest zawsze wstawianie i sprawdzanie błędu naruszenia PK i ignorowanie, ponieważ jest to nadmiarowe wstawianie.


4
UPDATE Orders Order
SET Order.Quantity =  Order.Quantity - 1
WHERE SomeCondition(Order)

O ile wiem, w SQL nie ma wbudowanego wsparcia dla INSERT-OR-UPDATE. Proponuję utworzyć procedurę składowaną lub użyć zapytania warunkowego, aby to osiągnąć. Tutaj znajdziesz zbiór rozwiązań dla różnych baz danych.


Możesz otrzymać błąd składni, rzucając zarezerwowane słowo ORDER w ten sposób ...
gahooa

0

odpowiedzieć na drugie:

uczynić kolumnę unikalną i przechwycić wyjątek, jeśli ma tę samą wartość.


0

@dotjoe Taniej jest zaktualizować i sprawdzić @@ rowcount, po czym wstawić fakt.

Wyjątki są drogie, a aktualizacje są częstsze

Sugestia: jeśli chcesz mieć najwyższą wydajność w swoim DAL, wprowadź interfejs użytkownika w unikalnym identyfikatorze wiersza, który ma zostać zaktualizowany, jeśli wstawia wartość null.

DAL powinny być CRUD i nie muszą się martwić, że są bezpaństwowcami.

Jeśli uczynisz to bezstanowym, przy dobrych indeksach nie zobaczysz różnicy z następującą instrukcją SQL vs 1. IF (wybierz górny 1 * formularz x, gdzie PK = @ ID) Wstaw else aktualizacja

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.