2009-11-16 17 views
17

Myślę, że to dość powszechny problem.Jak napisać ograniczenie dotyczące maksymalnej liczby wierszy w postgresql?

Mam tabelę user(id INT ...) i tabelę photo(id BIGINT, owner INT). Właściciel to referencja pod numerem user(id).

Chciałbym dodać ograniczenie do zdjęcia w tabeli, które uniemożliwiłoby więcej niż powiedzmy 10 zdjęć, aby wprowadzić bazę danych dla każdego użytkownika.

Jaki jest najlepszy sposób na zapisanie tego?

Thx!

Odpowiedz

18

Quassnoi ma rację; wyzwalacz byłby najlepszym sposobem osiągnięcia tego.

Oto kod:

CREATE OR REPLACE FUNCTION enforce_photo_count() RETURNS trigger AS $$ 
DECLARE 
    max_photo_count INTEGER := 10; 
    photo_count INTEGER := 0; 
    must_check BOOLEAN := false; 
BEGIN 
    IF TG_OP = 'INSERT' THEN 
     must_check := true; 
    END IF; 

    IF TG_OP = 'UPDATE' THEN 
     IF (NEW.owner != OLD.owner) THEN 
      must_check := true; 
     END IF; 
    END IF; 

    IF must_check THEN 
     -- prevent concurrent inserts from multiple transactions 
     LOCK TABLE photos IN EXCLUSIVE MODE; 

     SELECT INTO photo_count COUNT(*) 
     FROM photos 
     WHERE owner = NEW.owner; 

     IF photo_count >= max_photo_count THEN 
      RAISE EXCEPTION 'Cannot insert more than % photos for each user.', max_photo_count; 
     END IF; 
    END IF; 

    RETURN NEW; 
END; 
$$ LANGUAGE plpgsql; 


CREATE TRIGGER enforce_photo_count 
    BEFORE INSERT OR UPDATE ON photos 
    FOR EACH ROW EXECUTE PROCEDURE enforce_photo_count(); 

włączyłem tabeli blokowania w celu uniknięcia sytuacji, w której dwa równoległe tansactions liczyłbym zdjęcia dla użytkownika, zobaczyć, że obecna liczba to 1 poniżej limitu, a następnie zarówno wkładka , co spowodowałoby, że przekroczysz limit 1. Jeśli nie jest to dla ciebie problemem, najlepiej usunąć blokadę, która może stać się wąskim gardłem z wieloma wstawkami/aktualizacjami.

+0

Jeszcze jedno: niestety, wszystkie instrukcje IF na początku wyzwalacza nie mogą być połączone w jeden "IF TG_OP =" INSERT "LUB (TG_OP =" UPDATE "I NEW.owner! = OLD.owner) TO ... "ponieważ PLPGSQL nie obsługuje zwarć. –

7

Nie można zapisać takiego ograniczenia w deklaracji tabeli.

Istnieją pewne obejścia:

  • utworzyć wyzwalacz, który będzie sprawdzić liczbę zdjęć dla każdego użytkownika
  • utworzyć kolumnę że zachowałaby kolejność zdjęć, upewnij (user_id, photo_order)UNIQUE i dodać CHECK(photo_order BETWEEN 1 AND 10)
+1

Czy nie musiałbyś wymuszać unikalności w zamówieniu zdjęć? Jak to zrobić? – ahnbizcad

2

Jeszcze jedno podejście polegałoby na dodaniu kolumny "photo_count" do tabeli użytkowników, zaktualizowaniu jej za pomocą wyzwalaczy, aby odzwierciedlić rzeczywistość, i dodaniu go do kontroli w celu wymuszenia maksymalnej liczby zdjęć.

Po drugie, wiemy, że w dowolnym momencie (bez liczenia) wiemy, ile zdjęć ma użytkownik.

Z drugiej strony - podejście zaproponowane przez Quassnoi jest również całkiem fajne, ponieważ daje możliwość zmiany kolejności zdjęć na wypadek, gdyby użytkownik tego chciał.

Powiązane problemy