Wystąpił problem polegający na tym, że moja sekwencja kluczy podstawowych nie jest zsynchronizowana z wierszami tabeli.
Oznacza to, że po wstawieniu nowego wiersza pojawia się duplikat błędu klucza, ponieważ sekwencja sugerowana w typie danych szeregowych zwraca liczbę, która już istnieje.
Wydaje się, że jest to spowodowane importem / przywróceniem niewłaściwego utrzymywania sekwencji.
postgresql
primary-key
database-sequence
meleyal
źródło
źródło
Odpowiedzi:
Źródło - Ruby Forum
źródło
SELECT setval('your_table_id_seq', coalesce((select max(id)+1 from your_table), 1), false);
SELECT setval('your_seq',(SELECT GREATEST(MAX(your_id)+1,nextval('your_seq'))-1 FROM your_table))
pg_get_serial_sequence
można użyć, aby uniknąć niepoprawnych założeń dotyczących nazwy sekwencji. Spowoduje to zresetowanie sekwencji w jednym ujęciu:Lub bardziej zwięźle:
Jednak ta forma nie może poprawnie obsługiwać pustych tabel, ponieważ max (id) ma wartość null i nie można ustawić wartości 0, ponieważ byłoby to poza zakresem sekwencji. Jednym z obejść tego problemu jest skorzystanie ze
ALTER SEQUENCE
składni, tjMa jednak
ALTER SEQUENCE
ograniczone zastosowanie, ponieważ nazwa sekwencji i wartość restartu nie mogą być wyrażeniami.Wydaje się, że najlepszym rozwiązaniem uniwersalnym jest wywoływanie
setval
z fałszem jako trzecim parametrem, co pozwala nam określić „następną wartość do użycia”:To zaznacza wszystkie moje pola:
Na koniec zauważ, że
pg_get_serial_sequence
działa tylko wtedy, gdy sekwencja jest własnością kolumny. Będzie tak w przypadku, gdy kolumna inkrementująca została zdefiniowana jakoserial
typ, jednak jeśli sekwencja została dodana ręcznie, należy upewnićALTER SEQUENCE .. OWNED BY
się, że również zostanie wykonana.tzn. jeśli
serial
do utworzenia tabeli użyto typu, wszystko powinno działać:Ale jeśli sekwencje zostały dodane ręcznie:
źródło
setval()
ustawiania bieżącej wartości inextval()
już zwróci bieżącą wartość +1.Najkrótszy i najszybszy sposób:
tbl_id
będącserial
kolumną tabelitbl
, rysując z sekwencjitbl_tbl_id_seq
(która jest domyślną nazwą automatyczną).Jeśli nie znasz nazwy dołączonej sekwencji (która nie musi być w domyślnej formie), użyj
pg_get_serial_sequence()
:Nie ma tutaj błędu off-by-one. Według dokumentacji:
Odważny nacisk moje.
Jeśli tabela może być pusta i zacząć od 1 w tym przypadku:
Nie możemy po prostu użyć postaci 2-paremater i zacząć od,
0
ponieważ dolna granica sekwencji wynosi domyślnie 1 (chyba że niestandardowe).Konkurencja
Nie ma jeszcze obrony przed równoczesną aktywnością sekwencji lub zapisuje do tabeli w powyższych zapytaniach. Jeśli to istotne, możesz zablokować tabelę w trybie wyłączności. Uniemożliwia jednoczesnym transakcjom zapisywanie większej liczby podczas próby synchronizacji. (Tymczasowo blokuje również nieszkodliwe zapisy, nie mieszając się z maksymalną liczbą).
Ale nie bierze pod uwagę klientów, którzy mogli wcześniej pobrać numery sekwencyjne bez żadnych blokad głównego stołu (co może się zdarzyć). Aby na to pozwolić, zwiększaj tylko bieżącą wartość sekwencji, nigdy jej nie zmniejszaj. Może się to wydawać paranoikiem, ale jest to zgodne z naturą sekwencji i obrony przed problemami współbieżności.
źródło
EXECUTE format()
(jak @ EB.) Jest istotną funkcją! Jak naprawić ten brak standardowej biblioteki w PostgreSQL ????Spowoduje to zresetowanie wszystkich sekwencji z publicznego, nie przyjmując żadnych założeń dotyczących nazw tabel lub kolumn. Testowany na wersji 8.4
źródło
substring(column_default, '''(.*)''')
zamiasttable_name || '_' || column_name || '_seq'
. Działa świetnie.quote_literal
Iquote_ident
funkcje, lub korzystniejformat
funkcja powinna być naprawdę tu stosowane.substring(column_default from 'nextval\(''(.+)''::regclass\)')
jawnie chwycić nazwę sekwencji. Działa jak urok.substring(column_default, '''(.*)''') instead of table_name || '_' || column_name || '_seq'
ALTER SEQUENCE nazwa_sekwencji RESTART Z (WYBIERZ max (id) FROM nazwa_tabeli);Nie działaSkopiowano z opóźnionej odpowiedzi:
źródło
To polecenie służy tylko do zmiany automatycznie generowanej wartości sekwencji kluczy w postgresql
Zamiast zera możesz podać dowolną liczbę, od której chcesz zrestartować sekwencję.
domyślna nazwa sekwencji to
"TableName_FieldName_seq"
. Na przykład, jeśli nazwa tabeli to"MyTable"
i nazwa pola to"MyID"
, nazwa sekwencji będzie"MyTable_MyID_seq"
.To odpowiedź jest taka sama jak odpowiedź @ murugesanponappan, ale w jego rozwiązaniu występuje błąd składniowy. nie można użyć zapytania podrzędnego
(select max()...)
walter
poleceniu. Tak więc albo musisz użyć stałej wartości liczbowej, albo musisz użyć zmiennej zamiast zapytania podrzędnego.źródło
Zresetuj wszystkie sekwencje, bez założeń dotyczących nazw, z wyjątkiem tego, że kluczem podstawowym każdej tabeli jest „id”:
źródło
pg_get_serial_sequence(''"' || tablename || '"''
EXECUTE format( 'SELECT setval(pg_get_serial_sequence(%L, %L), coalesce(max(id),0) + 1, false) FROM %I;', $1,$2,$1 );
Funkcje te są obarczone niebezpieczeństwem, gdy nazwy sekwencji, nazwy kolumn, nazwy tabel lub nazwy schematów mają zabawne znaki, takie jak spacje, znaki interpunkcyjne i tym podobne. Napisałem to:
Możesz wywołać ją dla pojedynczej sekwencji, przekazując jej identyfikator OID, a ona zwróci najwyższy numer używany przez dowolną tabelę, która ma domyślną sekwencję; lub możesz uruchomić go z takim zapytaniem, aby zresetować wszystkie sekwencje w bazie danych:
Używając innej jakości możesz zresetować tylko sekwencję w określonym schemacie i tak dalej. Na przykład, jeśli chcesz dostosować sekwencje w schemacie „publicznym”:
Zauważ, że z powodu działania setval () nie musisz dodawać 1 do wyniku.
Na zakończenie muszę ostrzec, że niektóre bazy danych wydają się mieć domyślne ustawienia łączące z sekwencjami w sposób, który nie pozwala katalogom systemowym mieć pełnych informacji na ich temat. Dzieje się tak, gdy widzisz takie rzeczy w psql \ d:
Zauważ, że wywołanie nextval () w tej domyślnej klauzuli ma rzutowanie :: text oprócz rzutowania :: regclass. Myślę, że jest to spowodowane tym, że bazy danych są pg_dump'ed ze starych wersji PostgreSQL. To, co się stanie, to funkcja powyższej tabeli sekwencja_max_value () zignoruje taką tabelę. Aby rozwiązać problem, możesz ponownie zdefiniować klauzulę DOMYŚLNĄ, aby odwoływała się do sekwencji bezpośrednio bez rzutowania:
Następnie psql wyświetla go poprawnie:
Jak tylko to naprawisz, funkcja działa poprawnie dla tej tabeli, jak również dla wszystkich innych, które mogą używać tej samej sekwencji.
źródło
newmax := r.max::bigint;
aby działało poprawnie dla mnie.'SELECT max(' || quote_ident(colname) || ') FROM '
=>'SELECT max(' || quote_ident(colname) || '::bigint) FROM '
zauważ dodaną::bigint
obsadę w zapytaniu budowanym dynamicznie.Jeszcze inny plpgsql - resetuje tylko jeśli
max(att) > then lastval
komentowanie wiersza
--execute format('alter sequence
spowoduje wyświetlenie listy, a nie zresetowanie wartościźródło
Zresetuj całą sekwencję z publicznego
źródło
Sugeruję to rozwiązanie znalezione na wiki Postgres. Aktualizuje wszystkie sekwencje twoich tabel.
Jak korzystać (z wiki postgres):
Przykład:
Artykuł oryginalny (również z poprawką dotyczącą własności sekwencji) tutaj
źródło
Oto niektóre naprawdę hardcorowe odpowiedzi, zakładam, że kiedyś było bardzo źle, kiedy o to pytano, ponieważ wiele odpowiedzi tutaj nie działa w wersji 9.3. Dokumentacja od wersji 8.0 daje odpowiedź do tego samego pytania:
Ponadto, jeśli musisz zająć się rozróżnianiem wielkości liter w nazwach sekwencji, możesz to zrobić w następujący sposób:
źródło
Ten problem występuje ze mną, gdy używam struktury encji do utworzenia bazy danych, a następnie zapełniam bazę danych danymi początkowymi, co powoduje niedopasowanie sekwencji.
Rozwiązałem go, tworząc skrypt do uruchomienia po zainicjowaniu bazy danych:
źródło
MAX("Id") + 1
działa najlepiej dla mnie, gdy sekwencja jest = do maksimum.Moja wersja używa pierwszej, z pewną kontrolą błędów ...
źródło
RAISE WARNING
dla mnie zidentyfikowano.Kładąc wszystko razem
naprawi
id'
sekwencję podanej tabeli (jak to zwykle konieczne na przykład w przypadku django).źródło
zanim jeszcze nie wypróbowałem kodu: poniżej zamieszczam wersję kodu SQL dla rozwiązań Klausa i user457226, które działały na moim komputerze [Postgres 8.3], z niewielkimi modyfikacjami dla Klausa i mojej wersji dla użytkownika 457226 jeden.
Rozwiązanie Klaus:
rozwiązanie user457226:
źródło
Sprawdź ponownie całą sekwencję w funkcji schematu publicznego
źródło
Aby ponownie uruchomić wszystkie sekwencje do 1, użyj:
źródło
Odpowiedź Klausa jest najbardziej użyteczna, wykonywana za krótką chwilę: musisz dodać DISTINCT w instrukcji select.
Jeśli jednak masz pewność, że żadna nazwa tabeli + kolumny nie może być równoważna dla dwóch różnych tabel, możesz również użyć:
który jest rozszerzeniem rozwiązania user457226 dla przypadku, gdy nazwa zainteresowanej kolumny nie jest „ID”.
źródło
Jeśli zobaczysz ten błąd podczas ładowania niestandardowych danych SQL do inicjalizacji, możesz tego uniknąć inaczej:
Zamiast pisać:
Usuń
id
(klucz podstawowy) z danych początkowychTo utrzymuje synchronizację sekwencji Postgres!
źródło
Ta odpowiedź jest kopią z mauro.
źródło
Spędziłem godzinę próbując uzyskać odpowiedź djsnowsill do pracy z bazą danych przy użyciu tabel i kolumn Mixed Case, a potem w końcu natknąłem się na rozwiązanie dzięki komentarzowi Manuela Darveau, ale pomyślałem, że mógłbym to zrobić dla wszystkich nieco jaśniej:
Ma to tę zaletę, że:
Aby wyjaśnić, problem polegał na tym, że
pg_get_serial_sequence
ciągi znaków opracowują to, o czym mówisz, więc jeśli to zrobisz:Uzyskuje się to za pomocą
''%1$I''
ciągu formatu,''
apostrof1$
oznacza pierwszy argument iI
oznacza w cudzysłowieźródło
Brzydki hack, aby naprawić to za pomocą magii powłoki, nie jest to świetne rozwiązanie, ale może zainspirować innych z podobnymi problemami :)
źródło
źródło
Spróbuj ponownie .
AKTUALIZACJA: Jak wskazano w komentarzach, była to odpowiedź na pierwotne pytanie.
źródło
SELECT setval...
sprawia, że JDBC jest bork, więc oto sposób na zrobienie tego:źródło
Metoda aktualizacji wszystkich sekwencji w schemacie używanych jako identyfikator:
źródło
Po prostu uruchom poniżej polecenia:
źródło
Tutaj jest wiele dobrych odpowiedzi. Miałem tę samą potrzebę po przeładowaniu bazy danych Django.
Ale potrzebowałem:
Wydaje się, że jest to bardzo podobna potrzeba do pierwotnej prośby.
Dzięki Baldiry i Mauro wprowadziłem mnie na właściwy tor.
Następnie, aby wykonać i zobaczyć zmiany uruchom:
Zwroty
źródło