PostgreSQL'de tablo CREATE TABLE ad (sütun tip [DEFAULT ifade] [kısıt], ...); ile oluşturulur, yapısı ALTER TABLE ile değiştirilir: ADD COLUMN sütun ekler, DROP COLUMN siler, ALTER COLUMN ... TYPE ... USING tipi dönüştürür, RENAME yeniden adlandırır. Tabloyu tamamen kaldırmak için DROP TABLE, yapıyı koruyup bütün satırları hızla silmek için TRUNCATE kullanılır. PostgreSQL 18 ile üretilmiş sütunlar (GENERATED ALWAYS AS) varsayılan olarak sanaldır, yani okunurken hesaplanır.

Bu yazıda kılavuzun Data Definition bölümündeki tablo temelleri, varsayılan değerler, üretilmiş sütunlar ve tablo değiştirme sayfalarını, CREATE TABLE, ALTER TABLE, DROP TABLE ve TRUNCATE başvuru sayfalarındaki ayrıntılarla birleştiriyoruz. Kısıtlar primary key ve foreign key, tip seçimi veri tipleri, identity sütunları identity ve sequence yazısında. Örnekler PostgreSQL 18.1'de ornek_tablo veritabanında çalıştırıldı; serinin geri kalanı PostgreSQL öğrenme rehberi sayfasında. Çıktılarda yer kazanmak için CREATE ve INSERT gibi komutların onay satırlarını yer yer çıkardık; sorgu sonuçları ve hata mesajları olduğu gibidir.

Tablo temelleri ve adlandırma

Belgeye göre bir tablo kâğıt üzerindeki tablo gibidir: sütunların sayısı ve sırası sabittir, satır sayısı değişkendir. SQL satırların sırası hakkında hiçbir garanti vermez; sıra istiyorsanız sorguda açıkça ORDER BY yazmanız gerekir. SQL satırlara kendiliğinden benzersiz kimlik de atamaz, bu yüzden tamamen aynı iki satır bir tabloda bulunabilir; bunu önlemenin yolu birincil anahtardır. Bir tablonun alabileceği sütun sayısı, sütun tiplerine bağlı olarak 250 ile 1600 arasındadır ve belge buna yakın sayıda sütunu sorgulanabilir bir tasarım olarak görmez.

Tablo ve sütun adları SQL tanımlayıcısıdır. Tırnaksız adlar küçük harfe çevrilir, çift tırnaklı adlar ise büyük/küçük harfe duyarlı olur; en fazla 63 bayt kullanılır, uzun adlar kesilir. Bu kural en sık şaşırtan davranışlardan biridir:

sql
CREATE TABLE "Siparis" (Id integer, "Tutar" numeric);
SELECT * FROM Siparis;
SELECT id, "Tutar" FROM "Siparis";
text
psql:tb2.sql:26: ERROR:  relation "siparis" does not exist
LINE 1: SELECT * FROM Siparis;
                      ^
 id | Tutar 
----+-------
(0 rows)

Tabloyu tırnakla "Siparis" olarak oluşturduğumuz için tırnaksız Siparis küçük harfe çevrilip siparis olarak arandı ve bulunamadı. Tırnaksız yazılan Id sütunu ise id olarak kaydedildi. Belgenin önerisi tutarlı olmaktır: bir adı ya her zaman tırnakla ya hiç tırnaksız kullanın. En sorunsuz yol küçük harf, rakam ve alt çizgiden oluşan, tırnak gerektirmeyen adlar seçmektir. Tanımlayıcılar Türkçe harf içerebilir, ama uygulama kodunda ve farklı istemcilerde sorun çıkmaması için örneklerimizde ASCII adlar kullanıyoruz.

CREATE TABLE: sütunlar, varsayılanlar, üretilmiş sütunlar

CREATE TABLE: sütunlar, varsayılanlar, üretilmiş sütunlar: DEFAULT nasıl çalışır?, Üretilmiş sütunlar: VIRTUAL ve STORED

Aşağıdaki tablo bu yazının ana örneği. Fiyat ve KDV oranı için varsayılan değerler, KDV'li fiyat için sanal, stok değeri için depolanan bir üretilmiş sütun ve ekleme zamanı için now() varsayılanı tanımlıyoruz:

sql
CREATE TABLE urun (
    urun_no     integer,
    ad          text NOT NULL,
    fiyat       numeric(10,2) DEFAULT 0,
    kdv_orani   numeric(4,2) DEFAULT 20,
    kdvli_fiyat numeric GENERATED ALWAYS AS (round(fiyat * (1 + kdv_orani / 100), 2)),
    stok_degeri numeric GENERATED ALWAYS AS (fiyat * 10) STORED,
    eklenme     timestamptz DEFAULT now()
);
INSERT INTO urun (urun_no, ad, fiyat) VALUES (1, 'Çay bardağı', 45.00);
INSERT INTO urun (urun_no, ad, fiyat, kdv_orani) VALUES (2, 'Ekmek', 15.00, 1);
INSERT INTO urun (urun_no, ad) VALUES (3, 'Defter');
SELECT urun_no, ad, fiyat, kdv_orani, kdvli_fiyat, stok_degeri FROM urun ORDER BY urun_no;
text
 urun_no |     ad      | fiyat | kdv_orani | kdvli_fiyat | stok_degeri 
---------+-------------+-------+-----------+-------------+-------------
       1 | Çay bardağı | 45.00 |     20.00 |       54.00 |      450.00
       2 | Ekmek       | 15.00 |      1.00 |       15.15 |      150.00
       3 | Defter      |  0.00 |     20.00 |        0.00 |        0.00
(3 rows)

DEFAULT nasıl çalışır?

Varsayılan değer, bir satır eklenirken o sütun için değer verilmediğinde kullanılır; hiç tanımlanmamışsa varsayılan NULL'dur. Belgenin vurguladığı nokta, varsayılan ifadenin tablo oluşturulurken değil her ekleme sırasında hesaplanmasıdır; now() veya CURRENT_TIMESTAMP varsayılanı bu yüzden her satıra kendi ekleme zamanını yazar. Varsayılan ifadesi başka sütunlara başvuramaz ve alt sorgu içeremez. INSERT ve UPDATE içinde DEFAULT anahtar kelimesiyle bir sütunu açıkça varsayılanına döndürebilirsiniz. Sıra numarası üreten varsayılanlar için belge nextval() ve serial kısayolunu gösterir; günümüzde önerilen standart yol identity sütunlarıdır ve identity, serial ve sequence yazısında ele alınıyor.

Üretilmiş sütunlar: VIRTUAL ve STORED

Üretilmiş sütun, değeri her zaman aynı satırdaki diğer sütunlardan hesaplanan özel bir sütundur. Belge iki türü şöyle karşılaştırır: depolanan (STORED) sütun yazılırken hesaplanır ve normal bir sütun gibi yer kaplar, materialized view'a benzer; sanal (VIRTUAL) sütun hiç yer kaplamaz ve okunurken hesaplanır, view'a benzer. PostgreSQL 18 sürüm notlarına göre sanal üretilmiş sütunlar bu sürümle geldi ve varsayılan oldu; yazma sırasında hesaplanmasını istiyorsanız STORED yazmanız gerekir. Yukarıdaki \d çıktısında bu fark görülür:

bash
\d urun
text
                                                               Table "public.urun"
   Column    |           Type           | Collation | Nullable |                                     Default                                     
-------------+--------------------------+-----------+----------+---------------------------------------------------------------------------------
 urun_no     | integer                  |           |          | 
 ad          | text                     |           | not null | 
 fiyat       | numeric(10,2)            |           |          | 0
 kdv_orani   | numeric(4,2)             |           |          | 20
 kdvli_fiyat | numeric                  |           |          | generated always as (round(fiyat * (1::numeric + kdv_orani / 100::numeric), 2))
 stok_degeri | numeric                  |           |          | generated always as (fiyat * 10::numeric) stored
 eklenme     | timestamp with time zone |           |          | now()

Üretilmiş sütuna doğrudan yazılamaz; INSERT veya UPDATE içinde yalnızca DEFAULT verilebilir. Kaynak sütun değiştiğinde her iki tür de yeni değeri yansıtır:

sql
INSERT INTO urun (urun_no, ad, fiyat, kdvli_fiyat) VALUES (4, 'Kalem', 10, 12);
INSERT INTO urun (urun_no, ad, fiyat, kdvli_fiyat) VALUES (4, 'Kalem', 10, DEFAULT);
UPDATE urun SET fiyat = 50 WHERE urun_no = 1;
SELECT urun_no, fiyat, kdvli_fiyat, stok_degeri FROM urun WHERE urun_no = 1;
text
psql:tb1.sql:16: ERROR:  cannot insert a non-DEFAULT value into column "kdvli_fiyat"
DETAIL:  Column "kdvli_fiyat" is a generated column.
INSERT 0 1
UPDATE 1
 urun_no | fiyat | kdvli_fiyat | stok_degeri 
---------+-------+-------------+-------------
       1 | 50.00 |       60.00 |      500.00
(1 row)

Üretim ifadesine belgede sayılan kurallar uygulanır: yalnızca değişmez (immutable) fonksiyonlar kullanılabilir, alt sorgu ve başka tablolara başvuru yasaktır, başka bir üretilmiş sütuna başvurulamaz, üretilmiş sütunun varsayılanı veya identity tanımı olamaz ve bölümleme anahtarının parçası olamaz. Sanal sütunlar için ek kısıt vardır: kullanıcı tanımlı tip olamaz ve ifade yalnızca yerleşik fonksiyon ve tipleri kullanabilir. Zamanı yazmak için now() kullanmayı denediğimizde değişmezlik kuralı devreye girdi:

sql
CREATE TABLE hatali (a int, b timestamptz GENERATED ALWAYS AS (now()));
text
psql:tb1.sql:21: ERROR:  generation expression is not immutable
ÖzellikDEFAULTGENERATED VIRTUALGENERATED STORED
Ne zaman hesaplanırEkleme sırasında bir kezHer okunuştaHer yazışta
Diskte yer kaplar mıEvet (değer saklanır)HayırEvet
Elle değer verilebilir miEvetHayır, yalnızca DEFAULTHayır, yalnızca DEFAULT
Diğer sütunlara başvurabilir miHayırEvetEvet
now(), random() gibi değişken fonksiyonEvetHayırHayır
Kullanıcı tanımlı fonksiyon veya tipEvetHayırEvet (immutable olmalı)

ALTER TABLE ile yapıyı değiştirmek

ALTER TABLE ile yapıyı değiştirmek: Sütun eklemek, Veri tipini değiştirmek ve USING, Yeniden adlandırma, varsayılanı değiştirme, sütun silme

Belge, dolu ya da başka nesnelerin başvurduğu bir tabloyu silip yeniden oluşturmanın pratik olmadığını, bu yüzden ALTER TABLE komut ailesinin bulunduğunu belirtir. Bu komutlar tablonun verisini değil tanımını değiştirir. Aşağıda en sık kullanılan biçimleri sırayla deniyoruz.

Sütun eklemek

sql
ALTER TABLE urun ADD COLUMN barkod text;
ALTER TABLE urun ADD COLUMN aktif boolean NOT NULL DEFAULT true;
SELECT urun_no, barkod, aktif FROM urun ORDER BY urun_no;
text
 urun_no | barkod | aktif 
---------+--------+-------
       1 |        | t
       2 |        | t
       3 |        | t
       4 |        | t
(4 rows)

Yeni sütun mevcut satırlarda varsayılan değerle (verilmemişse NULL ile) dolar. Başvuru sayfasının Notes bölümü büyük tablolar için kritik bir ayrıntı verir: değişken olmayan (non-volatile) bir varsayılanla eklenen sütun için tablo yeniden yazılmaz; değer bir kez hesaplanıp tablo meta verisine kaydedilir ve eski satırlar okunurken döndürülür, bu yüzden komut büyük tablolarda da çok hızlıdır. clock_timestamp() gibi değişken bir varsayılan, depolanan bir üretilmiş sütun, identity sütunu veya kısıtlı bir domain tipi ise bütün tablonun ve indekslerinin yeniden yazılmasına yol açar. Sanal üretilmiş sütun eklemek hiçbir zaman yeniden yazma gerektirmez. Sütunla birlikte kısıt da tanımlanabilir, ancak varsayılan değer kısıtı sağlamıyorsa ekleme başarısız olur:

sql
ALTER TABLE urun ADD COLUMN birim text DEFAULT '' CHECK (birim <> '');
text
psql:tb2.sql:6: ERROR:  check constraint "urun_birim_check" of relation "urun" is violated by some row

Veri tipini değiştirmek ve USING

ALTER COLUMN ... TYPE yalnızca mevcut her değer yeni tipe örtük olarak dönüştürülebiliyorsa başarılı olur; daha karmaşık dönüşümler için USING ile yeni değerin eski değerden nasıl hesaplanacağını yazarsınız. Metin olarak tutulmuş ağırlıkları sayıya çevirmeyi denedik:

sql
ALTER TABLE urun ALTER COLUMN urun_no TYPE bigint;
ALTER TABLE urun ADD COLUMN agirlik text;
UPDATE urun SET agirlik = '0.25 kg' WHERE urun_no = 1;
UPDATE urun SET agirlik = '1 kg' WHERE urun_no = 2;
ALTER TABLE urun ALTER COLUMN agirlik TYPE numeric;
ALTER TABLE urun ALTER COLUMN agirlik TYPE numeric USING replace(agirlik, ' kg', '')::numeric;
SELECT urun_no, agirlik FROM urun ORDER BY urun_no;
text
ALTER TABLE
ALTER TABLE
UPDATE 1
UPDATE 1
psql:tb2.sql:12: ERROR:  column "agirlik" cannot be cast automatically to type numeric
HINT:  You might need to specify "USING agirlik::numeric".
ALTER TABLE
 urun_no | agirlik 
---------+---------
       1 |    0.25
       2 |       1
       3 |        
       4 |        
(4 rows)

Tip değişikliği normalde bütün tablonun ve indekslerinin yeniden yazılması demektir; büyük tablolarda uzun sürer ve geçici olarak iki kat disk alanı gerektirebilir. İstisna, USING değeri değiştirmiyorsa ve eski tip yeni tipe ikili uyumluysa ortaya çıkar; belge örnek olarak collation değişmediği sürece text ile varchar arasında geçişin indeksleri bile yeniden kurmadan yapılabildiğini verir. Belge ayrıca USING ifadesinin sütunun varsayılan değerine uygulanmadığını, bu yüzden dönüşüm başarısız olursa önce DROP DEFAULT, sonra tip değişikliği, en sonda yeni bir SET DEFAULT yapılmasını önerir. Sütuna bağlı kısıtları değişiklikten önce kaldırıp sonra uyarlanmış hâlleriyle eklemek de tavsiye edilir.

Yeniden adlandırma, varsayılanı değiştirme, sütun silme

sql
ALTER TABLE urun RENAME COLUMN agirlik TO agirlik_kg;
ALTER TABLE urun ALTER COLUMN kdv_orani SET DEFAULT 10;
ALTER TABLE urun DROP COLUMN fiyat;
ALTER TABLE urun DROP COLUMN fiyat CASCADE;
ALTER TABLE urun RENAME TO urunler;
text
ALTER TABLE
ALTER TABLE
psql:tb2.sql:18: ERROR:  cannot drop column fiyat of table urun because other objects depend on it
DETAIL:  column kdvli_fiyat of table urun depends on column fiyat of table urun
column stok_degeri of table urun depends on column fiyat of table urun
HINT:  Use DROP ... CASCADE to drop the dependent objects too.
psql:tb2.sql:19: NOTICE:  drop cascades to 2 other objects
DETAIL:  drop cascades to column kdvli_fiyat of table urun
drop cascades to column stok_degeri of table urun
ALTER TABLE
ALTER TABLE

SET DEFAULT mevcut satırları değiştirmez, yalnızca sonraki eklemeleri etkiler. fiyat sütununu silmek istediğimizde PostgreSQL'in bağımlılık takibi devreye girdi: iki üretilmiş sütun bu sütuna dayandığı için komut reddedildi ve CASCADE ile birlikte o sütunlar da silindi. Belge, sütuna başka bir tablonun yabancı anahtarı başvuruyorsa bu kısıtın da sessizce silinmeyeceğini, CASCADE gerektiğini belirtir. Bir başka önemli not: DROP COLUMN sütunu fiziksel olarak silmez, yalnızca SQL'e görünmez yapar; disk alanı satırlar güncellendikçe zamanla geri kazanılır. Alanı hemen geri almak için tabloyu yeniden yazan bir ALTER TABLE biçimi çalıştırılabilir.

Birden çok değişikliği tek komutta virgülle yazmak mümkündür ve belgeye göre bunun asıl amacı, gereken tablo taramalarını veya yeniden yazmaları tek geçişte birleştirmektir:

sql
ALTER TABLE urunler DROP COLUMN barkod, DROP COLUMN aktif;

Üretilmiş sütunlar için de iki özel biçim vardır: ALTER COLUMN ... SET EXPRESSION AS (ifade) üretim ifadesini değiştirir (depolanan sütunlarda mevcut veriyi yeniden yazar), DROP EXPRESSION ise depolanan bir üretilmiş sütunu normal sütuna çevirir; belge bu ikinci biçimin şimdilik yalnızca depolanan sütunlarda desteklendiğini belirtir.

DROP TABLE ve bağımlılıklar

DROP TABLE tabloyu, indekslerini, kurallarını, tetikleyicilerini ve kısıtlarını siler. Tabloya bir view ya da başka bir tablonun yabancı anahtarı başvuruyorsa CASCADE gerekir. Belgedeki ince ayrım şudur: CASCADE bağımlı view'ı tamamen siler, ama yabancı anahtar durumunda yalnızca kısıtı siler, diğer tabloya dokunmaz. Var olmayan bir tabloyu silmek hatadır; betiklerde IF EXISTS bunu bildirime çevirir:

sql
CREATE TABLE kategori (id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY, ad text);
CREATE TABLE kalem (id integer GENERATED ALWAYS AS IDENTITY, kategori_id integer REFERENCES kategori, ad text);
CREATE VIEW kategori_adlari AS SELECT ad FROM kategori;
DROP TABLE kategori;
DROP TABLE kategori CASCADE;
DROP TABLE IF EXISTS yok_tablo;
text
psql:tb3.sql:20: ERROR:  cannot drop table kategori because other objects depend on it
DETAIL:  constraint kalem_kategori_id_fkey on table kalem depends on table kategori
view kategori_adlari depends on table kategori
HINT:  Use DROP ... CASCADE to drop the dependent objects too.
psql:tb3.sql:21: NOTICE:  drop cascades to 2 other objects
DETAIL:  drop cascades to constraint kalem_kategori_id_fkey on table kalem
drop cascades to view kategori_adlari
DROP TABLE
psql:tb2.sql:31: NOTICE:  table "yok_tablo" does not exist, skipping
DROP TABLE

\d kalem ile baktığımızda kalem tablosunun yerinde durduğunu ama yabancı anahtarının kalktığını gördük. Benzer şekilde CREATE TABLE IF NOT EXISTS aynı adda bir tablo varsa yalnızca bildirim verir; belge, var olan tablonun oluşturulmak istenene benzediğinin hiçbir garantisi olmadığını hatırlatır. Yani bu seçenek yapı farklarını yakalamaz.

TRUNCATE: tabloyu hızla boşaltmak

TRUNCATE: tabloyu hızla boşaltmak: DELETE FROM t, TRUNCATE t, DROP TABLE t

TRUNCATE bir veya birden çok tablonun bütün satırlarını siler. Belgeye göre etkisi koşulsuz bir DELETE ile aynıdır, ama tabloyu taramadığı için daha hızlıdır ve disk alanını sonradan VACUUM beklemeden hemen geri verir. Karşılığında tablo üzerinde ACCESS EXCLUSIVE kilit alır ve eşzamanlı bütün işlemleri bekletir; satır silme tetikleyicilerini (ON DELETE) çalıştırmaz, yalnızca ON TRUNCATE tetikleyicilerini çalıştırır. Başka tablolardan yabancı anahtarla başvurulan bir tablo, o tablolar da aynı komutta boşaltılmadıkça boşaltılamaz:

sql
INSERT INTO kategori (ad) VALUES ('Kırtasiye'), ('Gıda');
INSERT INTO kalem (kategori_id, ad) VALUES (1, 'Silgi'), (2, 'Peynir');
TRUNCATE kategori;
TRUNCATE kategori, kalem RESTART IDENTITY;
INSERT INTO kategori (ad) VALUES ('Temizlik') RETURNING id;
text
psql:tb3.sql:6: ERROR:  cannot truncate a table referenced in a foreign key constraint
DETAIL:  Table "kalem" references "kategori".
HINT:  Truncate table "kalem" at the same time, or use TRUNCATE ... CASCADE.
TRUNCATE TABLE
 id 
----
  1
(1 row)

RESTART IDENTITY tablolara ait sequence'leri baştan başlattığı için yeni kayıt yeniden 1 numarasını aldı; varsayılan CONTINUE IDENTITY numaraları olduğu gibi bırakır. CASCADE ise başvuran bütün tabloları otomatik olarak işleme ekler; belge bu seçenekte istemeden veri kaybedebileceğiniz konusunda açıkça uyarır. Bir başka önemli özellik: TRUNCATE transaction güvenlidir, yani çevreleyen transaction geri alınırsa veri geri gelir:

sql
INSERT INTO kategori (ad) VALUES ('Elektronik');
BEGIN;
TRUNCATE kategori CASCADE;
ROLLBACK;
SELECT ad FROM kategori;
text
INSERT 0 1
BEGIN
psql:tb3.sql:15: NOTICE:  truncate cascades to table "kalem"
TRUNCATE TABLE
ROLLBACK
     ad     
------------
 Elektronik
(1 row)

Belge yine de TRUNCATE'in MVCC açısından güvenli olmadığını belirtir: boşaltmadan önce alınmış anlık görüntüyle çalışan eşzamanlı transaction'lar tabloyu boş görebilir. Eşzamanlı erişim gerekiyorsa DELETE kullanın; satır silmenin ayrıntıları INSERT, UPDATE, DELETE yazısında.

KomutNe silerGeri alınabilir miNot
DELETE FROM tSatırları (WHERE ile seçerek de)Evet, transaction içindeSatır tetikleyicileri çalışır, alan VACUUM ile geri kazanılır
TRUNCATE tBütün satırlarıEvet, transaction içindeHızlı, ACCESS EXCLUSIVE kilit, MVCC güvenli değil
DROP TABLE tTabloyu ve tanımınıEvet, transaction içindeBağımlı nesneler için CASCADE gerekir

Diğer kullanışlı CREATE TABLE biçimleri

LIKE yan tümcesi başka bir tablonun sütun adlarını, tiplerini ve NOT NULL kısıtlarını kopyalar; INCLUDING ALL ile varsayılanlar, identity tanımları (yeni ve ayrı sequence ile), üretim ifadeleri, CHECK kısıtları, indeksler ve PRIMARY KEY, UNIQUE, EXCLUDE kısıtları da gelir; seçenek listesinde yabancı anahtar yoktur. Belgeye göre kopyalanan tablo oluşturulduktan sonra kaynaktan tamamen bağımsızdır. TEMP tablolar oturum sonunda (istenirse transaction sonunda) kendiliğinden silinir ve oturuma özel bir geçici şemada yaşar; autovacuum geçici tablolara erişemediği için büyük geçici tablolarda elle ANALYZE çalıştırmanız önerilir. UNLOGGED tablolar WAL'a yazılmadığı için daha hızlıdır ama çökme veya temiz olmayan kapanış sonrasında otomatik olarak boşaltılır ve standby sunuculara kopyalanmaz.

sql
CREATE TABLE kalem_arsiv (LIKE kalem INCLUDING ALL);
CREATE TEMP TABLE gecici_sepet (urun text, adet integer DEFAULT 1);
\dt
text
                List of tables
   Schema   |     Name     | Type  |  Owner   
------------+--------------+-------+----------
 pg_temp_47 | gecici_sepet | table | postgres
 public     | Siparis      | table | postgres
 public     | kalem        | table | postgres
 public     | kalem_arsiv  | table | postgres
 public     | urunler      | table | postgres
(5 rows)

Sık yapılan hatalar

  • Satır sırasına güvenmek: SQL satır sırası garanti etmez; sıra gerekiyorsa her sorguda ORDER BY yazın.
  • Karışık harfli tırnaklı adlar: "Siparis" gibi adlar her sorguda tırnak ister; küçük harfli adlar kullanın.
  • Üretilmiş sütuna değer yazmaya çalışmak: Yalnızca DEFAULT verilebilir; uygulama ORM'iniz bütün sütunları gönderiyorsa bu sütunları yazma listesinden çıkarın.
  • Büyük tabloda değişken varsayılanla sütun eklemek: clock_timestamp() gibi bir varsayılan bütün tabloyu yeniden yazar; önce varsayılansız ekleyip UPDATE ile doldurmak ve sonra SET DEFAULT vermek belgede önerilen yoldur.
  • CASCADE'i düşünmeden kullanmak: DROP ... CASCADE ve TRUNCATE ... CASCADE sizin listelemediğiniz nesneleri de etkiler; önce CASCADE'siz çalıştırıp hata mesajındaki bağımlılık listesini okuyun.
  • IF NOT EXISTS'i şema göçü sanmak: Tablo varsa komut hiçbir şey yapmaz; farklı yapıdaki eski tabloyu güncellemez.

Sık Sorulan Sorular

Sütunların sırasını değiştirebilir miyim?

ALTER TABLE belgesinde sütun sırasını değiştiren bir biçim yoktur; sütunlar eklendikleri sırada kalır. Sorgularda istediğiniz sırayı seçim listesinde belirtin; fiziksel sıra gerçekten gerekiyorsa yeni bir tablo oluşturup veriyi taşımanız gerekir.

Sanal üretilmiş sütuna indeks koyabilir miyim?

PostgreSQL 18.1 üzerinde denediğimizde hayır: CREATE INDEX ON sanal_dene (b); komutu ERROR: indexes on virtual generated columns are not supported hatası verdi. 18.4 sürüm notları bu mesajın yersiz çıktığı bazı durumları düzeltiyor, ama sanal sütunun kendisini indekslemek desteklenmiyor. İndekslenmesi gereken hesaplanmış değerler için STORED sütun ya da aynı ifade üzerinde bir ifade indeksi kullanın.

TRUNCATE ile DELETE arasında hangisini seçmeliyim?

Bütün tabloyu boşaltacaksanız ve tabloya o sırada başka oturumların erişmesi gerekmiyorsa TRUNCATE daha hızlıdır ve alanı hemen geri verir. Satırların bir kısmını siliyorsanız, satır tetikleyicilerinin çalışması gerekiyorsa veya tablo eşzamanlı kullanılıyorsa DELETE kullanın.

Tablonun tanımını SQL olarak nasıl görürüm?

psql'de \d+ tablo ayrıntılı yapıyı gösterir. Tam CREATE TABLE metnini almak için pg_dump --schema-only -t tablo komutu kullanılabilir; pg_dump yazısında seçenekleri anlatıyoruz.

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 · Primary key, foreign key ve kısıtlar · PostgreSQL veri tipleri · Identity ve sequence · INSERT, UPDATE, DELETE · PostgreSQL 18 yenilikleri