PostgreSQL'de otomatik artan bir ID sütunu için önerilen yol, SQL standardındaki GENERATED ALWAYS AS IDENTITY (ya da GENERATED BY DEFAULT AS IDENTITY) tanımıdır. Eski ve hâlâ yaygın olan serial/bigserial yazımı da aynı işi yapar; ikisi de arka planda bir sequence nesnesi kullanır. Sequence'ler nextval, currval ve setval fonksiyonlarıyla yönetilir ve CREATE SEQUENCE ile doğrudan da oluşturulabilir.

Bu yazı identity sütunlarının ALWAYS ve BY DEFAULT farkını, serial'in gerçekte neye açıldığını, sequence fonksiyonlarını, sequence'i ilerletme ve sıfırlama yollarını, değerlerdeki boşlukların nedenini, önbellek ve döngü seçeneklerini ve elle ID eklendikten sonra çıkan "duplicate key" hatasının çözümünü çalıştırılmış örneklerle anlatır. Örnekler PostgreSQL 18.1 üzerinde çalıştırıldı; serinin geri kalanı için PostgreSQL öğrenme rehberi.

GENERATED ALWAYS AS IDENTITY

Identity sütunu, kendisine bağlı örtük bir sequence'ten değer alan özel bir sütundur. INSERT sırasında sütuna değer verilmezse sequence'in sıradaki değeri yazılır. Sütun otomatik olarak NOT NULL olur. Sequence'lerin desteklediği tipler smallint, integer ve bigint olduğu için identity sütunu da bu tiplerden biri olmalıdır:

sql
CREATE TABLE musteri (
    id    bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    ad    text NOT NULL,
    sehir text
);
INSERT INTO musteri (ad, sehir) VALUES ('Ayşe Yılmaz', 'İstanbul'), ('Mehmet Kaya', 'Ankara');
INSERT INTO musteri (ad, sehir) VALUES ('Zeynep Demir', 'İzmir') RETURNING id;
SELECT * FROM musteri ORDER BY id;
text
 id 
----
  3
(1 row)

 id |      ad      |  sehir   
----+--------------+----------
  1 | Ayşe Yılmaz  | İstanbul
  2 | Mehmet Kaya  | Ankara
  3 | Zeynep Demir | İzmir
(3 rows)

Üretilen değeri uygulamaya döndürmenin en temiz yolu RETURNING id kullanmaktır; ayrı bir sorguyla en büyük ID'yi okumak eşzamanlı eklemelerde yanlış sonuç verebilir. RETURNING ve PostgreSQL 18 ile gelen OLD/NEW desteği INSERT, UPDATE, DELETE ve RETURNING yazısında.

ALWAYS ile BY DEFAULT farkı

İki seçenek, kullanıcının sütuna açıkça değer yazmaya çalıştığında ne olacağını belirler. ALWAYS seçildiğinde açık bir değer yalnızca INSERT komutuna OVERRIDING SYSTEM VALUE eklenirse kabul edilir; UPDATE ile sütun yalnızca DEFAULT değerine güncellenebilir. Değer yerine DEFAULT anahtar kelimesini yazmak her zaman serbesttir:

sql
INSERT INTO musteri (id, ad) VALUES (10, 'Ali Veli');
INSERT INTO musteri (id, ad) OVERRIDING SYSTEM VALUE VALUES (10, 'Ali Veli');
INSERT INTO musteri (id, ad) VALUES (DEFAULT, 'Fatma Şahin') RETURNING id;
UPDATE musteri SET id = 99 WHERE id = 1;
text
ERROR:  cannot insert a non-DEFAULT value into column "id"
DETAIL:  Column "id" is an identity column defined as GENERATED ALWAYS.
HINT:  Use OVERRIDING SYSTEM VALUE to override.
INSERT 0 1
 id 
----
  4
(1 row)

INSERT 0 1
ERROR:  column "id" can only be updated to DEFAULT
DETAIL:  Column "id" is an identity column defined as GENERATED ALWAYS.

BY DEFAULT seçildiğinde ise kullanıcının verdiği değer önceliklidir; sütun sıradan bir varsayılan değerli sütun gibi davranır ve normal biçimde güncellenebilir. Belgelerin ifadesiyle ALWAYS, yanlışlıkla açık değer yazılmasına karşı daha fazla koruma sağlar. Toplu veri aktarımında bir istisna vardır: COPY komutunda kullanıcının verdiği değerler bu ayardan bağımsız olarak her zaman kullanılır. psql'de \d komutu sütunun türünü gösterir:

bash
\d musteri
text
                        Table "public.musteri"
 Column |  Type  | Collation | Nullable |           Default            
--------+--------+-----------+----------+------------------------------
 id     | bigint |           | not null | generated always as identity
 ad     | text   |           | not null | 
 sehir  | text   |           |          | 
Indexes:
    "musteri_pkey" PRIMARY KEY, btree (id)

Elle ID ekledikten sonra gelen duplicate key hatası

En sık karşılaşılan sequence sorunu şudur: bir tabloya ID değerleri açıkça verilerek veri aktarılır (örneğin başka bir sistemden taşıma), sequence ise bundan habersiz 1'de kalır. Sonraki ilk normal INSERT zaten var olan bir ID üretir:

sql
CREATE TABLE urun (
    id  int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    ad  text NOT NULL
);
INSERT INTO urun (id, ad) VALUES (1, 'Kalem'), (2, 'Defter'), (3, 'Silgi');
INSERT INTO urun (ad) VALUES ('Cetvel');
text
ERROR:  duplicate key value violates unique constraint "urun_pkey"
DETAIL:  Key (id)=(1) already exists.

Çözüm, sequence'i tablodaki en büyük değere çekmektir. Sütuna bağlı sequence'in adını tahmin etmek yerine pg_get_serial_sequence(tablo, sutun) ile alın; fonksiyon hem identity hem serial sütunlar için çalışır. İki argümanlı setval değeri "kullanılmış" olarak işaretler, yani bir sonraki nextval bir fazlasını döndürür:

sql
SELECT pg_get_serial_sequence('urun', 'id') AS sequence_adi;
SELECT setval(pg_get_serial_sequence('urun', 'id'), (SELECT max(id) FROM urun));
INSERT INTO urun (ad) VALUES ('Cetvel') RETURNING id;
text
    sequence_adi    
--------------------
 public.urun_id_seq
(1 row)

 setval 
--------
      3
(1 row)

 id 
----
  4
(1 row)

Belgelerdeki CREATE SEQUENCE örneği de aynı kalıbı COPY FROM sonrası için önerir. Tablo boşsa max(id) NULL döner; bu kümede setval o durumda hata vermeden NULL döndürdü ve sequence'e dokunmadı. Boş tablolarda RESTART kullanın ya da değeri coalesce ile verin. Veri yükleme konusu COPY ile CSV içe ve dışa aktarma, hata kodunun kendisi sık hatalar ve SQLSTATE kodları yazısında.

serial gerçekte ne yapar?

serial gerçekte ne yapar? Standart, Açık değer yazma, Sütun tanımında görünen, Sequence ayarları

Belgelere göre smallserial, serial ve bigserial gerçek tipler değil, bir kısaltmadır. id serial yazdığınızda PostgreSQL tablo_sutun_seq adında bir sequence oluşturur, sütunu integer NOT NULL DEFAULT nextval('tablo_sutun_seq') olarak tanımlar ve sequence'i OWNED BY ile sütuna bağlar; böylece sütun ya da tablo silinince sequence de silinir. serial integer, bigserial bigint, smallserial smallint sütun üretir:

sql
CREATE TABLE eski_tablo (
    id  serial PRIMARY KEY,
    ad  text
);
\d eski_tablo
text
                            Table "public.eski_tablo"
 Column |  Type   | Collation | Nullable |                Default                 
--------+---------+-----------+----------+----------------------------------------
 id     | integer |           | not null | nextval('eski_tablo_id_seq'::regclass)
 ad     | text    |           |          | 
Indexes:
    "eski_tablo_pkey" PRIMARY KEY, btree (id)
ÖzellikGENERATED ... AS IDENTITYserial
StandartSQL standardıPostgreSQL'e özgü kısaltma
Açık değer yazmaALWAYS ile engellenir, BY DEFAULT ile serbesther zaman serbest
Sütun tanımında görünengenerated ... as identitynextval(...) varsayılanı
Sequence ayarlarıCREATE TABLE veya ALTER TABLE içindeALTER SEQUENCE ile ayrıca
SıfırlamaALTER TABLE ... ALTER COLUMN ... RESTARTALTER SEQUENCE ... RESTART ya da setval
NOT NULLotomatikotomatik
BenzersizlikPRIMARY KEY veya UNIQUE gerekirPRIMARY KEY veya UNIQUE gerekir

Belgeler, 2 milyarın üzerinde (2 üzeri 31) tanımlayıcıya ihtiyaç duyulabilecek tablolarda bigserial kullanılmasını önerir; aynı mantık identity sütunlarında bigint seçmek için de geçerlidir. Yeni tablolarda identity tercih etmenizin temel nedeni, ALWAYS ile sağladığı koruma ve sequence'in sütunun parçası olarak yönetilmesidir.

serial sütunu identity'ye çevirmek

Mevcut bir serial sütunu identity'ye çevirmek için belgelenmiş ALTER TABLE biçimlerini sırayla uygulayabilirsiniz: varsayılanı kaldırın, eski sequence'i silin ve sütuna ADD GENERATED ... AS IDENTITY ekleyin. Örneği boş bir tabloda çalıştırdık; veri içeren bir tabloda yeni identity 1'den başlayacağı için ardından ALTER COLUMN id RESTART WITH ile en büyük değerin bir fazlasını vermeniz gerekir:

sql
ALTER TABLE eski_tablo ALTER COLUMN id DROP DEFAULT;
DROP SEQUENCE eski_tablo_id_seq;
ALTER TABLE eski_tablo ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY;
\d eski_tablo
text
                         Table "public.eski_tablo"
 Column |  Type   | Collation | Nullable |             Default              
--------+---------+-----------+----------+----------------------------------
 id     | integer |           | not null | generated by default as identity
 ad     | text    |           |          | 
Indexes:
    "eski_tablo_pkey" PRIMARY KEY, btree (id)

BY DEFAULT ile ALWAYS arasında sonradan ALTER COLUMN id SET GENERATED ALWAYS ile geçiş yapılabilir. Identity sütununa bağlı sequence ise ayrıca silinemez; PostgreSQL cannot drop sequence urun_id_seq because column id of table urun requires it hatası verir. Identity özelliğini kaldırmak için ALTER COLUMN id DROP IDENTITY kullanılır. Bu işlemler sırasında alınan kilitler için CREATE TABLE ve ALTER TABLE yazısına bakabilirsiniz.

CREATE SEQUENCE ve sequence fonksiyonları

CREATE SEQUENCE ve sequence fonksiyonları: nextval(seq) sequence'i ilerletip yeni değeri döndürür. Bu işlem atomiktir..., currval(seq) bu oturumda o sequence için en son nextval...

Tablo sütununa bağlı olmayan numaralar (fatura numarası, sipariş kodu gibi) için doğrudan bir sequence oluşturabilirsiniz. Başlıca seçenekler: AS ile tip (smallint, integer, varsayılan bigint), START WITH ile başlangıç, INCREMENT BY ile artış (negatif değer azalan sequence üretir), MINVALUE/MAXVALUE ile sınırlar, CYCLE ile sınıra gelince başa dönme ve CACHE ile önceden ayrılan değer sayısı.

sql
CREATE SEQUENCE fatura_no AS integer START WITH 1000 INCREMENT BY 10;
SELECT currval('fatura_no');
SELECT nextval('fatura_no') AS bir, nextval('fatura_no') AS iki;
SELECT currval('fatura_no') AS currval, lastval() AS lastval;
SELECT last_value, is_called FROM fatura_no;
text
ERROR:  currval of sequence "fatura_no" is not yet defined in this session
 bir  | iki  
------+------
 1000 | 1010
(1 row)

 currval | lastval 
---------+---------
    1010 |    1010
(1 row)

 last_value | is_called 
------------+-----------
       1010 | t
(1 row)

Fonksiyonların anlamı:

  • nextval(seq) sequence'i ilerletip yeni değeri döndürür. Bu işlem atomiktir; aynı anda çağıran oturumlar her zaman farklı değer alır.
  • currval(seq) bu oturumda o sequence için en son nextval ile alınan değeri döndürür. Oturumda henüz nextval çağrılmadıysa yukarıdaki hatayı verir. Başka oturumların çağrılarından etkilenmez, bu yüzden eşzamanlı ortamda güvenlidir.
  • lastval() aynı şeyi, oturumda en son hangi sequence kullanıldıysa onun için yapar.
  • setval(seq, deger) sequence'i ayarlar; bir sonraki nextval değerin bir fazlasını verir. Üçüncü argüman false verilirse bir sonraki nextval tam olarak o değeri döndürür.

Sequence adı regclass tipinde bir argüman olarak verilir; metin yazdığınızda PostgreSQL onu sequence'in kimliğine kendisi çevirir. Bir sequence tablosundan doğrudan SELECT yaparak last_value ve is_called alanlarını görebilirsiniz. setval farkını iki çağrıyla görelim:

sql
SELECT setval('fatura_no', 5000);
SELECT nextval('fatura_no');
SELECT setval('fatura_no', 5000, false);
SELECT nextval('fatura_no');
text
 setval 
--------
   5000
(1 row)

 nextval 
---------
    5010
(1 row)

 setval 
--------
   5000
(1 row)

 nextval 
---------
    5000
(1 row)

Sequence değerini biçimli bir koda dönüştürmek için metin fonksiyonlarıyla birleştirebilirsiniz; örneğin format('FTR-%s-%s', extract(year FROM date '2026-03-15'), lpad(nextval('fatura_no')::text, 6, '0')) bu oturumda FTR-2026-005010 üretti. format ve lpad için string fonksiyonları yazısına bakın. Fonksiyonların yetki gereksinimleri de belgelerde tanımlıdır: nextval için USAGE ya da UPDATE, setval için UPDATE, currval için USAGE ya da SELECT yetkisi gerekir; ayrıntılar GRANT ve REVOKE yazısında.

Sequence sıfırlama ve yeniden başlatma

Bir sequence'i baştan başlatmanın üç yolu vardır. Bağımsız sequence için ALTER SEQUENCE ... RESTART WITH n, identity sütunu için ALTER TABLE ... ALTER COLUMN ... RESTART WITH n, tabloyu boşaltırken ise TRUNCATE ... RESTART IDENTITY:

sql
ALTER SEQUENCE fatura_no RESTART WITH 1;
SELECT nextval('fatura_no');

ALTER TABLE musteri ALTER COLUMN id RESTART WITH 100;
INSERT INTO musteri (ad) VALUES ('Can Aydın') RETURNING id;

TRUNCATE siparis RESTART IDENTITY;
INSERT INTO siparis (kod) VALUES ('Y-1') RETURNING id;
text
 nextval 
---------
       1
(1 row)

 id  
-----
 100
(1 row)

 id 
----
  1
(1 row)

RESTART ile setval arasında önemli bir fark vardır. Belgelere göre RESTART transaction'a bağlıdır ve aynı sequence'ten numara almak isteyen eşzamanlı transaction'ları bekletir; setval ise hemen görünür olur ve transaction geri alınsa bile geri alınmaz. START WITH değerini ALTER SEQUENCE ile değiştirmek mevcut değeri etkilemez, yalnızca parametresiz RESTART komutlarının kullanacağı değeri belirler. TRUNCATE tabloda ve RESTART IDENTITY ile sequence'lerde özel kilit aldığı için çalışan bir sistemde dikkatle kullanılmalıdır.

Numaralardaki boşluklar normaldir

Sequence değerleri geri verilmez. Bir transaction nextval ile değer aldıktan sonra geri alınsa bile o değer harcanmış olur; böylece eşzamanlı transaction'lar birbirini beklemeden numara alabilir. Belgeler ayrıca ON CONFLICT içeren bir INSERT komutunun çakışmayı fark etmeden önce eklenecek satırı hesapladığını, yani nextval çağrısının yine yapıldığını belirtir. Sonuç olarak hiçbir satır silinmese de boşluklar oluşur:

sql
CREATE TABLE siparis (id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, kod text UNIQUE);
INSERT INTO siparis (kod) VALUES ('S-1');
BEGIN;
INSERT INTO siparis (kod) VALUES ('S-2');
ROLLBACK;
INSERT INTO siparis (kod) VALUES ('S-3');
INSERT INTO siparis (kod) VALUES ('S-1') ON CONFLICT (kod) DO NOTHING;
INSERT INTO siparis (kod) VALUES ('S-4');
SELECT * FROM siparis ORDER BY id;
text
 id | kod 
----+-----
  1 | S-1
  3 | S-3
  5 | S-4
(3 rows)

2 numarası geri alınan transaction'da, 4 numarası çakışan ve hiç eklenmeyen satırda harcandı. Bu yüzden belgeler sequence'lerin "boşluksuz" numaralandırma için kullanılamayacağını açıkça söyler. Yasal olarak kesintisiz numara gerektiren bir belge numarası gibi ihtiyaçlarda, sayaç tutan bir tabloyu özel kilitle güncellemek mümkündür, ancak belgelerin uyarısına göre bu yöntem özellikle çok sayıda eşzamanlı transaction olduğunda sequence'ten çok daha pahalıdır. Kilit mekanizması için kilitler ve deadlock, geri alma davranışı için BEGIN, COMMIT ve ROLLBACK yazısına bakın. ON CONFLICT ayrıntıları UPSERT ve MERGE yazısında.

Bir uyarı daha: çökme durumunda, commit edilmemiş bir transaction'daki nextval sonucunun kalıcı depolamaya yazılıp yazılmadığı belirsizdir. Veritabanı içinde bu zararsızdır, ama bir sequence değerini veritabanı dışında (örneğin müşteriye gönderilen bir kodda) kullanacaksanız önce nextval çağrısını içeren transaction'ı commit edin.

Sınırlar, CYCLE ve CACHE

Artan bir sequence'in varsayılan üst sınırı tipinin en büyük değeridir. Sınıra ulaşıldığında varsayılan NO CYCLE davranışıyla nextval hata verir; CYCLE seçeneğiyle en küçük değere döner:

sql
CREATE SEQUENCE kucuk AS smallint MAXVALUE 3;
SELECT nextval('kucuk'), nextval('kucuk'), nextval('kucuk');
SELECT nextval('kucuk');

CREATE SEQUENCE donen MAXVALUE 3 CYCLE;
SELECT nextval('donen') FROM generate_series(1, 5);
text
 nextval | nextval | nextval 
---------+---------+---------
       1 |       2 |       3
(1 row)

ERROR:  nextval: reached maximum value of sequence "kucuk" (3)
 nextval 
---------
       1
       2
       3
       1
       2
(5 rows)

Birincil anahtar sequence'lerinde CYCLE kullanmak, döngü başa döndüğünde çakışma hatası demektir; bu seçenek yalnızca tekrarın sorun olmadığı sayaçlar içindir. integer bir identity sütununun 2.147.483.647 sınırına yaklaşması da aynı hata ile sonuçlanır; büyüyebilecek tablolarda baştan bigint seçmek bu riski ortadan kaldırır.

CACHE n her oturumun bir seferde n değer ayırmasını sağlar; varsayılan 1, yani önbellek yoktur. Belgelere göre önbellek 1'den büyükse oturum kapanırken kullanılmamış ayrılmış değerler kaybolur (yeni boşluklar oluşur) ve oturumlar arasında değerler artık sırayla üretilmez: A oturumu 1-10'u, B oturumu 11-20'yi ayırmışsa B'nin 11'i, A'nın 2'sinden önce verilebilir. Bu durumda yalnızca değerlerin farklı olduğuna güvenebilirsiniz, sıralarına değil. setval çağrısı da diğer oturumlar önbelleklerindeki değerleri bitirene kadar onlar tarafından fark edilmez.

Sequence'leri listelemek

pg_sequences sistem görünümü bütün sequence'leri tip, başlangıç, artış, sınır ve son değer bilgisiyle listeler. Belgelere göre last_value, sequence'ten henüz okunmamışsa ya da kullanıcının yetkisi yoksa NULL görünür; önbellek kullanılıyorsa dağıtılan son değerden büyük olabilir. Bu örnekte hiç kullanılmamış eski_tablo_id_seq satırında değer boş:

sql
SELECT sequencename, data_type, start_value, increment_by, max_value, cycle, last_value
FROM pg_sequences WHERE schemaname = 'public' ORDER BY sequencename;
text
   sequencename    | data_type | start_value | increment_by |      max_value      | cycle | last_value 
-------------------+-----------+-------------+--------------+---------------------+-------+------------
 donen             | bigint    |           1 |            1 |                   3 | t     |          2
 eski_tablo_id_seq | integer   |           1 |            1 |          2147483647 | f     |           
 fatura_no         | integer   |        1000 |           10 |          2147483647 | f     |          1
 kucuk             | smallint  |           1 |            1 |                   3 | f     |          3
 musteri_id_seq    | bigint    |           1 |            1 | 9223372036854775807 | f     |          4
 siparis_id_seq    | bigint    |           1 |            1 | 9223372036854775807 | f     |          5
 urun_id_seq       | integer   |           1 |            1 |          2147483647 | f     |          4
(7 rows)

psql'de \ds komutu da sequence'leri listeler; psql komutlarının tamamı psql komutları yazısında. Yedek alırken sequence değerlerinin de taşındığını unutmayın; PostgreSQL 18 sürüm notları pg_dump ve pg_dumpall için normalde dışarıda kalan sequence verisini de döken --sequence-data seçeneğini ekledi. Yedekleme ayrıntıları pg_dump ve pg_restore yazısında.

Sık yapılan hatalar

Sık yapılan hatalar: Veri aktardıktan sonra sequence'i ilerletmeyi unutmak ve "duplicate key" hatası..., Identity sütununun benzersizliği kendiliğinden sağladığını sanmak; PRIMARY...
  • Veri aktardıktan sonra sequence'i ilerletmeyi unutmak ve "duplicate key" hatası almak. setval(pg_get_serial_sequence(...), max(id)) ile düzeltin.
  • Identity sütununun benzersizliği kendiliğinden sağladığını sanmak; PRIMARY KEY ya da UNIQUE ekleyin.
  • Eklenen satırın ID'sini SELECT max(id) ile okumak; RETURNING id ya da aynı oturumda currval kullanın.
  • Boşluksuz numara beklemek; geri alınan transaction'lar ve ON CONFLICT boşluk bırakır.
  • Büyüyecek tablolarda integer seçip üst sınıra ulaşmak.
  • Sequence adını elle tahmin etmek: serial sütunlu bir tabloyu eski adından yeni adına çevirdiğimizde pg_get_serial_sequence('yeni', 'id') hâlâ public.eski_id_seq döndürdü. Adı her zaman bu fonksiyonla alın.
  • Birincil anahtar sequence'ine CYCLE vermek.

Sık Sorulan Sorular

PostgreSQL'de AUTO_INCREMENT karşılığı nedir?

id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY. Belgeler serial tiplerini diğer veritabanlarındaki AUTO_INCREMENT özelliğine benzetir, ancak yeni tablolar için standart identity sözdizimi daha iyi bir seçimdir. MySQL ile genel farklar için MySQL ve PostgreSQL karşılaştırması yazısına bakabilirsiniz.

Sequence'i nasıl sıfırlarım?

Identity sütunu için ALTER TABLE tablo ALTER COLUMN id RESTART WITH 1, bağımsız sequence için ALTER SEQUENCE ad RESTART WITH 1, tabloyu da boşaltacaksanız TRUNCATE tablo RESTART IDENTITY. Tabloda veri varken sıfırlamak çakışma hatalarına yol açar.

ALWAYS mu BY DEFAULT mu seçmeliyim?

Uygulamanın ID üretmesini istemiyorsanız ALWAYS; yanlışlıkla elle değer yazılmasını engeller. Düzenli olarak dışarıdan ID'li veri aktarıyorsanız BY DEFAULT daha pratiktir, ama her aktarımdan sonra sequence'i ilerletmeniz gerekir.

Tahmin edilemeyen bir ID gerekiyorsa ne kullanmalıyım?

Sıralı tam sayılar dışarıdan tahmin edilebilir. Bu bir sorunsa uuid tipine bakın; PostgreSQL 18 zamana göre sıralanabilen UUID üreten uuidv7() fonksiyonunu ekledi. Ayrıntılar PostgreSQL veri tipleri yazısında.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: PostgreSQL öğrenme rehberi · CREATE TABLE ve ALTER TABLE · kısıtlar · INSERT ve RETURNING · UPSERT ve MERGE · veri tipleri · pg_dump ile yedek