Saya mengalami masalah bahwa urutan kunci utama saya tidak sinkron dengan baris tabel saya.
Yaitu, ketika saya menyisipkan baris baru saya mendapatkan kesalahan kunci duplikat karena urutan yang tersirat dalam datatype serial mengembalikan nomor yang sudah ada.
Tampaknya disebabkan oleh impor / mengembalikan tidak mempertahankan urutan dengan benar.
postgresql
primary-key
database-sequence
meleyal
sumber
sumber
Jawaban:
Sumber - Forum Ruby
sumber
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
dapat digunakan untuk menghindari asumsi yang salah tentang nama urutan. Ini mengatur ulang urutan dalam satu pemotretan:Atau lebih ringkas:
Namun formulir ini tidak dapat menangani tabel kosong dengan benar, karena maks (id) adalah nol, dan Anda juga tidak dapat menetapkan 0 karena itu akan berada di luar kisaran urutan. Salah satu solusi untuk ini adalah dengan menggunakan
ALTER SEQUENCE
sintaks yaituTetapi
ALTER SEQUENCE
penggunaannya terbatas karena nama urutan dan nilai restart tidak dapat berupa ekspresi.Tampaknya solusi serba guna terbaik adalah memanggil
setval
dengan false sebagai parameter ke-3, memungkinkan kami menentukan "nilai selanjutnya yang akan digunakan":Ini mencentang semua kotak saya:
Akhirnya, perhatikan bahwa
pg_get_serial_sequence
hanya berfungsi jika urutan dimiliki oleh kolom. Ini akan menjadi kasus jika kolom tambahan didefinisikan sebagaiserial
tipe, namun jika urutan ditambahkan secara manual maka perlu untuk memastikanALTER SEQUENCE .. OWNED BY
juga dilakukan.yaitu jika
serial
jenis digunakan untuk pembuatan tabel, ini semua harus bekerja:Tetapi jika urutan ditambahkan secara manual:
sumber
setval()
tetapkan nilai saat ini, dannextval()
sudah akan mengembalikan nilai saat ini +1.Cara terpendek dan tercepat :
tbl_id
menjadiserial
kolom tabeltbl
, menggambar dari urutantbl_tbl_id_seq
(yang merupakan nama otomatis default).Jika Anda tidak tahu nama urutan terlampir (yang tidak harus dalam bentuk default), gunakan
pg_get_serial_sequence()
:Tidak ada kesalahan satu-persatu di sini. Per dokumentasi:
Penekanan berani saya.
Jika tabel dapat kosong dan mulai dari 1 dalam kasus ini:
Kita tidak bisa hanya menggunakan bentuk 2-paremater dan mulai dengan
0
karena batas urutan yang lebih rendah adalah 1 secara default (kecuali disesuaikan).Konkurensi
Tidak ada pertahanan terhadap aktivitas urutan bersamaan atau menulis ke tabel dalam pertanyaan di atas, belum. Jika itu relevan, Anda dapat mengunci tabel dalam mode eksklusif. Itu menjaga transaksi bersamaan dari menulis angka yang lebih tinggi saat Anda mencoba untuk menyinkronkan. (Ini juga untuk sementara memblokir penulisan yang tidak berbahaya yang tidak mengacaukan jumlah maksimum.)
Tapi itu tidak memperhitungkan klien yang mungkin telah mengambil nomor urut sebelumnya tanpa kunci di tabel utama, (yang dapat terjadi). Untuk memungkinkannya juga, hanya meningkatkan nilai urutan saat ini, jangan pernah menguranginya. Ini mungkin tampak paranoid, tapi itu sesuai dengan sifat dari sekuens dan bertahan terhadap masalah konkurensi.
sumber
EXECUTE format()
(seperti @ EB.) Adalah fungsi penting! Bagaimana cara memperbaiki kekurangan perpustakaan standar ini di PostgreSQL ????Ini akan mengatur ulang semua urutan dari publik tanpa membuat asumsi tentang nama tabel atau kolom. Diuji pada versi 8.4
sumber
substring(column_default, '''(.*)''')
bukantable_name || '_' || column_name || '_seq'
. Bekerja dengan sempurna.quote_literal
danquote_ident
, atau lebih baikformat
fungsi, harus benar-benar digunakan di sini.substring(column_default from 'nextval\(''(.+)''::regclass\)')
secara eksplisit mengambil nama urutan. Bekerja seperti pesona.substring(column_default, '''(.*)''') instead of table_name || '_' || column_name || '_seq'
ALTER SEQUENCE sequence_name RESTART WITH (SELECT max (id) FROM table_name);Tidak bekerjaDisalin dari @tardate answer:
sumber
Perintah ini hanya untuk mengubah nilai urutan kunci yang dibuat secara otomatis di postgresql
Di tempat nol Anda dapat menempatkan nomor dari mana Anda ingin memulai kembali urutan.
nama urutan default akan
"TableName_FieldName_seq"
. Misalnya, jika nama tabel Anda"MyTable"
dan nama bidang Anda"MyID"
, maka nama urutan Anda akan"MyTable_MyID_seq"
.Jawaban ini sama dengan jawaban @ murugesanponappan, tetapi ada kesalahan sintaksis dalam solusinya. Anda tidak dapat menggunakan sub kueri
(select max()...)
dalamalter
perintah. Sehingga Anda harus menggunakan nilai angka tetap atau Anda perlu menggunakan variabel sebagai pengganti sub kueri.sumber
Setel ulang semua urutan, tidak ada asumsi tentang nama kecuali bahwa kunci utama setiap tabel adalah "id":
sumber
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 );
Fungsi-fungsi ini penuh dengan bahaya ketika nama urutan, nama kolom, nama tabel atau nama skema memiliki karakter lucu seperti spasi, tanda baca, dan sejenisnya. Saya telah menulis ini:
Anda dapat memanggilnya untuk urutan tunggal dengan melewatkannya OID dan itu akan mengembalikan angka tertinggi yang digunakan oleh tabel apa pun yang memiliki urutan sebagai default; atau Anda dapat menjalankannya dengan kueri seperti ini, untuk mengatur ulang semua urutan dalam basis data Anda:
Dengan menggunakan qual yang berbeda, Anda hanya dapat mereset urutan dalam skema tertentu, dan seterusnya. Misalnya, jika Anda ingin menyesuaikan urutan dalam skema "publik":
Perhatikan bahwa karena cara kerja setval (), Anda tidak perlu menambahkan 1 ke hasilnya.
Sebagai catatan penutup, saya harus memperingatkan bahwa beberapa database tampaknya memiliki default yang menghubungkan ke urutan dengan cara yang tidak membiarkan katalog sistem memiliki informasi lengkap tentang mereka. Ini terjadi ketika Anda melihat hal-hal seperti ini di psql's:
Perhatikan bahwa panggilan nextval () dalam klausa default memiliki cast :: text di samping :: regclass cast. Saya pikir ini disebabkan oleh database yang pg_dump'ed dari versi PostgreSQL lama. Apa yang akan terjadi adalah bahwa fungsi sequence_max_value () di atas akan mengabaikan tabel seperti itu. Untuk memperbaiki masalah, Anda dapat mendefinisikan kembali klausa DEFAULT untuk merujuk ke urutan langsung tanpa pemain:
Kemudian psql menampilkannya dengan benar:
Segera setelah Anda memperbaikinya, fungsi berfungsi dengan benar untuk tabel ini serta semua yang lain yang mungkin menggunakan urutan yang sama.
sumber
newmax := r.max::bigint;
untuk membuatnya bekerja dengan benar untuk saya.'SELECT max(' || quote_ident(colname) || ') FROM '
=>'SELECT max(' || quote_ident(colname) || '::bigint) FROM '
perhatikan::bigint
pemain yang ditambahkan dalam kueri build secara dinamis.Namun lain plpgsql - me-reset hanya jika
max(att) > then lastval
juga mengomentari baris
--execute format('alter sequence
akan memberikan daftar, tidak benar-benar mengatur ulang nilainyasumber
Setel ulang semua urutan dari publik
sumber
Saya menyarankan solusi ini ditemukan di postgres wiki. Ini memperbarui semua urutan tabel Anda.
Cara menggunakan (dari postgres wiki):
Contoh:
Artikel asli (juga dengan perbaikan untuk kepemilikan urutan) di sini
sumber
Beberapa jawaban yang sangat hardcore di sini, saya berasumsi dulu benar-benar buruk di sekitar waktu ketika ini telah ditanyakan, karena banyak jawaban dari sini tidak bekerja untuk versi 9.3. The dokumentasi sejak versi 8.0 menyediakan jawaban untuk pertanyaan ini sangat:
Juga, jika Anda perlu mengurus nama urutan case-sensitive, itulah cara Anda melakukannya:
sumber
Masalah ini terjadi dengan saya ketika menggunakan kerangka entitas untuk membuat database dan kemudian menyemai database dengan data awal, ini membuat urutan ketidakcocokan.
Saya mengatasinya dengan Membuat skrip untuk dijalankan setelah seeding basis data:
sumber
MAX("Id") + 1
ini bekerja paling baik untuk saya ketika urutan = ke max.Versi saya menggunakan yang pertama, dengan beberapa pemeriksaan kesalahan ...
sumber
RAISE WARNING
identifikasi untuk saya.Menyatukan semuanya
akan memperbaiki '
id'
urutan tabel yang diberikan (seperti yang biasanya diperlukan dengan Django misalnya).sumber
sebelum saya belum mencoba kode tersebut: berikut ini saya memposting versi untuk kode sql untuk solusi Klaus dan user457226 yang bekerja pada pc saya [Postgres 8.3], dengan hanya beberapa penyesuaian kecil untuk Klaus satu dan versi saya untuk yang pengguna457226.
Solusi Klaus:
solusi user457226:
sumber
Periksa kembali semua urutan dalam fungsi skema publik
sumber
Untuk memulai kembali semua urutan ke 1 gunakan:
sumber
Jawaban Klaus adalah yang paling berguna, dan jangan lewatkan: Anda harus menambahkan DISTINCT dalam pernyataan pilih.
Namun, jika Anda yakin bahwa tidak ada nama tabel + kolom yang bisa sama dengan dua tabel yang berbeda, Anda juga dapat menggunakan:
yang merupakan perpanjangan dari solusi user457226 untuk kasus ketika beberapa nama kolom yang tertarik bukan 'ID'.
sumber
Jika Anda melihat kesalahan ini ketika Anda memuat data SQL khusus untuk inisialisasi, cara lain untuk menghindari ini adalah:
Alih-alih menulis:
Hapus
id
(kunci utama) dari data awalIni menjaga urutan Postgres tetap sinkron!
sumber
Jawaban ini adalah salinan dari mauro.
sumber
Saya menghabiskan satu jam mencoba untuk mendapatkan jawaban djsnowsill untuk bekerja dengan database menggunakan tabel dan kolom Mixed Case, kemudian akhirnya menemukan solusi berkat komentar dari Manuel Darveau, tapi saya pikir saya bisa membuatnya sedikit lebih jelas untuk semua orang:
Ini memiliki manfaat:
Untuk menjelaskan, masalahnya adalah
pg_get_serial_sequence
membutuhkan string untuk mengetahui apa yang Anda maksud, jadi jika Anda melakukannya:Ini dicapai menggunakan
''%1$I''
string format,''
membuat tanda kutip1$
berarti arg pertama, danI
berarti dalam tanda kutipsumber
sumber
Peretasan yang jelek untuk memperbaikinya menggunakan beberapa shell magic, bukan solusi yang hebat tetapi mungkin menginspirasi orang lain dengan masalah yang sama :)
sumber
Coba pengindeksan ulang .
UPDATE: Seperti yang ditunjukkan dalam komentar, ini adalah jawaban untuk pertanyaan awal.
sumber
SELECT setval...
membuat JDBC bork, jadi inilah cara yang kompatibel dengan Java untuk melakukan ini:sumber
Metode untuk memperbarui semua urutan dalam skema Anda yang digunakan sebagai ID:
sumber
Jalankan saja perintah di bawah ini:
sumber
Ada banyak jawaban bagus di sini. Saya memiliki kebutuhan yang sama setelah memuat ulang basis data Django saya.
Tetapi saya membutuhkan:
Tampaknya kebutuhan ini sangat mirip dengan apa yang diminta aslinya.
Terima kasih kepada Baldiry dan Mauro membuat saya berada di jalur yang benar.
Kemudian untuk Jalankan dan Lihat perubahan dijalankan:
Kembali
sumber