PostgreSQL’de veri değiştiren bir CTE, işlemleri ortak bir anlık görüntüyle tek bir ifadede birleştirir. İşlem içindeki ayrı ifadeler sırayla çalışır ve önceki yazma işlemlerini okuyabilir. Her işlemin girdisini nasıl alması gerektiğine göre seçim yapın.

Mac’te Terminal kullanan bir geliştirici için somut görev, sentetik bir makale iş akışının tek bir SQL ifadesinde mi yoksa birden fazla işlemsel sorguda mı yer alacağına karar vermektir. Aşağıdaki örneklerde görünürlük farkı, uygun bir CTE iş akışı ve eksiksiz bir node-postgres işlemi gösterilmektedir.

İşlemleri bir CTE’de birleştirdiğinizde ne değişir?

Veri değiştiren bir CTE, WITH içinde INSERT, UPDATE, DELETE veya güncel PostgreSQL’de MERGE içerir. Bileşenleri aynı anlık görüntüyü paylaşır; fiziksel değişiklik sıraları öngörülemez. Başka bir bileşenin değiştirilmiş satırlara ihtiyacı varsa bunları RETURNING ile aktarın. CTE’leri yukarıdan aşağıya yazmak, işlemsel yürütme sırası belirlemez. PostgreSQL: WITH Sorguları

BEGIN ve COMMIT içindeki ayrı SQL ifadelerinin kendi ifade sınırları vardır. PostgreSQL’in varsayılan Read Committed yalıtım düzeyinde her ifade yeni bir anlık görüntü alır ve kendi işleminin daha önce yaptığı değişiklikleri görebilir. Diğer işlemlerin tamamladığı işlemler de ifadeler arasında görünür hâle gelebilir. PostgreSQL: İşlem Yalıtımı

Her iki yaklaşım da işlemin ya hep ya hiç biçiminde gerçekleşmesini sağlayabilir. Açık bir işlem bloğu yoksa PostgreSQL her ifadeyi örtük bir işlem içinde yürütür; açık bir işlem birden fazla ifadeyi gruplar. Veri değiştiren bir CTE, daha büyük bir işlemin içindeki tek bir ifade de olabilir. PostgreSQL: İşlemler

Gereksinim Uygun başlangıç noktası
Değiştirilen satırları doğrudan başka bir tabloya aktarmak RETURNING kullanan bir CTE
Önceki bir ifade tabloyu değiştirdikten sonra tabloyu okumak İşlem içindeki sıralı ifadeler
Aynı satırı bilinçli olarak iki aşamada değiştirmek Sıralı ifadeler veya son hesaplamayı tek bir güncellemede birleştirmek
Sonraki sorguyu seçmeden önce ara sonucu incelemek Uygulama mantığıyla birlikte sıralı ifadeler
Bağımsız istekler arasında bekleme süresini azaltmak Aktarım seçeneklerini SQL anlambiliminden ayrı değerlendirmek

Bu karar yardımı, belgelenmiş görünürlük kurallarını izler. Önce bağımlılığı tanımlayın: Sonraki işlem döndürülen bir ilişkiye mi, tabloyu yeni bir okumayla görmeye mi, yoksa JavaScript’in vereceği bir karara mı ihtiyaç duyuyor? Bu soru, kaç işlemin WITH içine sığdığını saymaktan daha yararlıdır.

Görünürlük farkını yerel ortamda nasıl yeniden oluşturabilirsiniz?

Mac’inizde psql içinde mevcut bir PostgreSQL 18 bağlantısı veya bir SQL düzenleyicisi kullanın. Aşağıdaki betiğin tamamını tek bir oturumda çalıştırın. Yalnızca geçici bir tablo oluşturur, tek bir sentetik makale kullanır ve ROLLBACK ile sona erer. Beklenen değerler belgelere dayanarak çıkarılmıştır; hazırlık sırasında veritabanı örnekleri çalıştırılmamıştır.

BEGIN ISOLATION LEVEL READ COMMITTED;

CREATE TEMP TABLE cte_demo_articles (
    id integer PRIMARY KEY,
    title text NOT NULL,
    stage text NOT NULL
) ON COMMIT DROP;

INSERT INTO cte_demo_articles (id, title, stage)
VALUES (1, 'Sample article', 'draft');

WITH edited AS (
    UPDATE cte_demo_articles
    SET stage = 'edited'
    WHERE id = 1
    RETURNING id, stage
)
SELECT a.stage AS table_stage,
       e.stage AS returned_stage
FROM cte_demo_articles AS a
JOIN edited AS e ON e.id = a.id;
-- Expected: table_stage = draft, returned_stage = edited

SELECT stage FROM cte_demo_articles WHERE id = 1;
-- Expected: edited, because this is a subsequent statement.

UPDATE cte_demo_articles SET stage = 'draft' WHERE id = 1;

UPDATE cte_demo_articles SET stage = 'edited' WHERE id = 1;
UPDATE cte_demo_articles
SET stage = 'ready'
WHERE id = 1 AND stage = 'edited';

SELECT stage FROM cte_demo_articles WHERE id = 1;
-- Expected: ready

ROLLBACK;

İlk sorguda tablo taraması draft okurken CTE’nin çıktısı edited içerir. Sonraki ifade tablodan edited okur. Bu, değiştirme yapan ifadenin içinde hedef tabloyu okuma ile CTE’nin döndürdüğü satırları okuma arasındaki belgelenmiş farkı gösterir. PostgreSQL: WITH Sorguları

Son iki güncelleme, ayrı ifadelerde aynı satırı bilerek değiştirir. Bunları kardeş veri değiştiren CTE’lerde birleştirmek desteklenmez: PostgreSQL tek bir ifade içinde aynı satırda iki değişiklik yapılmasını güvenilir biçimde gerçekleştirmez. Önceki bir CTE’ye başvurmak bu kısıtlamayı ortadan kaldırmaz. PostgreSQL: SELECT

Veri değiştiren bir CTE ne zaman uygundur?

Seçilen makale satırlarını arşive taşımak yararlı bir ilişkisel görevdir: silme işlemi tam olarak hangi satırların taşınacağını belirler ve döndürdüğü ilişki ekleme işleminin girdisini sağlar. DELETE ile RETURNING silinen satırların içeriğini gösterir; UPDATE ile varsayılan çıktı güncellenmiş değerleri içerir. PostgreSQL: Değiştirilen Satırlardan Veri Döndürme

Bu bağımsız örnek kendi tablolarını ve girdisini sağlar. Önceki örnek bittikten sonra aynı oturumda çalıştırın.

BEGIN;

CREATE TEMP TABLE move_demo_articles (
    id integer PRIMARY KEY,
    title text NOT NULL,
    stage text NOT NULL
) ON COMMIT DROP;

CREATE TEMP TABLE move_demo_archive (
    id integer PRIMARY KEY,
    title text NOT NULL,
    stage text NOT NULL
) ON COMMIT DROP;

INSERT INTO move_demo_articles (id, title, stage)
VALUES
    (1, 'Sample article A', 'ready'),
    (2, 'Sample article B', 'draft');

WITH moved AS (
    DELETE FROM move_demo_articles
    WHERE stage = 'ready'
    RETURNING id, title, stage
)
INSERT INTO move_demo_archive (id, title, stage)
SELECT id, title, stage
FROM moved
RETURNING id, title, stage;
-- Expected: article 1, with stage ready.

SELECT id, stage FROM move_demo_articles ORDER BY id;
-- Expected: article 2, with stage draft.

ROLLBACK;

Ekleme işlemi doğrudan moved girdisini kullanır. Veri değiştiren WITH, en üst düzey ifadeye bağlı olmalıdır. Çıktısı kullanılmasa bile veri değiştiren bir CTE tamamlanana kadar bir kez çalışır; RETURNING ifadesini çıkarmak, değişikliği değil, kullanılabilir sonuç ilişkisini ortadan kaldırır. PostgreSQL: WITH Sorguları

Hata durumunda işlem sınırı da önemlidir: ekleme başarısız olursa taşıma başarıyla tamamlanmaz. Açık bir işlemde, hata sonrasında ROLLBACK gönderin. Ara satırların başarıyla alınmasını, çevreleyen işlemin tamamlandığının kanıtı saymayın. PostgreSQL: İşlemler

node-postgres bağımlı ifadeleri nasıl çalıştırmalı?

Bir iş akışı, sonraki sorguyu göndermeden önce bir sonucu inceliyorsa aynı istemcide sıralı await çağrıları kullanın. node-postgres, işlemdeki her ifade için aynı istemcinin kullanılmasını gerektirir; işlem adımlarını ayrı pool.query() çağrılarıyla göndermek, bağlantı sürekliliğini sağlamaz. node-postgres: İşlemler

Ön koşullar Node.js, npm ve mevcut bir yerel PostgreSQL 18 veritabanı bağlantısıdır. Node projenizin dizininde Terminal’i açıp npm install pg çalıştırın. Aşağıdaki programın tamamını article-transaction.mjs olarak kaydedin, ardından node article-transaction.mjs çalıştırın. new Client() standart PostgreSQL bağlantı ortam değişkenlerini kullanır; varsayılanlar mevcut veritabanınızla eşleşmiyorsa bunları veritabanınıza göre yapılandırın. node-postgres: Bağlantı Kurma

import pg from 'pg';

const { Client } = pg;
const client = new Client();
await client.connect();

try {
  await client.query('BEGIN ISOLATION LEVEL READ COMMITTED');

  await client.query(`
    CREATE TEMP TABLE articles (
      id integer PRIMARY KEY,
      title text NOT NULL,
      stage text NOT NULL
    ) ON COMMIT DROP
  `);

  await client.query(
    'INSERT INTO articles VALUES ($1, $2, $3)',
    [1, 'Sample article', 'draft']
  );

  const first = await client.query(
    `UPDATE articles SET stage = $1
     WHERE id = $2 RETURNING id, stage`,
    ['edited', 1]
  );
  if (first.rowCount !== 1) {
    throw new Error('Expected one article');
  }

  const second = await client.query(
    `UPDATE articles SET stage = $1
     WHERE id = $2 AND stage = $3
     RETURNING id, stage`,
    ['ready', 1, 'edited']
  );
  if (second.rowCount !== 1) {
    throw new Error('Expected one edited article');
  }

  await client.query('COMMIT');
  console.log(second.rows);
} catch (error) {
  await client.query('ROLLBACK');
  throw error;
} finally {
  await client.end();
}

Beklenen çıktı satırında id: 1 ve stage: 'ready' bulunur. Geçici tablo, işlem tamamlandığında silinir. JavaScript sözdizimi Node.js ile denetlendi; veritabanında çalıştırma yapılmadı.

Sorgu çağrıları, node-postgres’in parametreli sorgu API’sine uygun olarak değerleri $1, $2 ve $3 üzerinden ayrı ayrı iletir. Her çağrı tek bir SQL ifadesi içerir. node-postgres: Sorgular

rowCount denetimi, beklenmedik bir sıfır satırlı güncellemeyi işlem tamamlanmadan açık bir hataya dönüştürür. rowCount komutun işlediği satır sayısını bildirirken rows döndürülen kayıtları içerir; RETURNING olmadan yapılan bir güncelleme satırları etkileyebilir ama boş bir rows dizisi döndürür. node-postgres: pg.Result

İfadeleri toplu göndermek SQL anlambilimini değiştirir mi?

Toplu gönderim, işin nasıl gönderildiğini açıklar. Birden fazla SQL ifadesini tek bir veri değiştiren CTE’ye dönüştürmez.

PostgreSQL’in simple-query protokolü noktalı virgülle ayrılmış ifadeleri kabul eder. Açık işlem denetimi yoksa tek bir simple Query iletisindeki ifadeler örtük bir işlemde çalışır. Bir hata, kalan ifadeleri durdurur. Extended protokolünün Parse iletisi yalnızca tek bir ifadeyi kabul eder; bu nedenle noktalı virgülle ayrılmış bir toplu gönderim, ayrı parametreli sorguların genel bir alternatifi değildir. PostgreSQL: İleti Akışı

Açık bir toplu gönderim ayrıca toplu gönderimin dışında hata yönetimi gerektirir: sondaki ROLLBACK ifadesine ulaşılmadan hata oluşursa geri alma işlemi çalışmaz. Başarısız işlemi sonlandırmak için ayrı bir geri alma isteği gönderin. PostgreSQL: Simple Query İçindeki Birden Fazla İfade

Güncel node-postgres belgeleri, isteğe bağlı pipelining özelliğini de açıklar. Bu özellik her yanıtı beklemeden istekleri gönderir; PostgreSQL ise bunları sırayla işler. Belgeler, işlemin sonraki sorgusu önceki bir sonuca bağlı olduğunda sıralı await çağrılarını önerir. Pipelining isteklerin zamanlamasını değiştirir; ortak bir CTE anlık görüntüsü oluşturmaz. node-postgres: Pipelining

Seçimi hangi sürüm ve yalıtım kısıtlamaları yönlendirmeli?

Bu makale için alınan güncel PostgreSQL belgeleri 18. sürümü tanımlar. PostgreSQL 16, veri değiştiren CTE gövdelerinde INSERT, UPDATE ve DELETE ifadelerine izin verir, ancak burada MERGE ifadesini desteklemez. 17. sürüm belgeleri MERGE ifadesini içerir ve sürüm notlarında MERGE RETURNING özelliğinin eklendiği belgelenir. PostgreSQL 16 iş akışında, daha yeni CTE sözdizimini kopyalamak yerine desteklenen veri değiştirme ifadelerini veya ayrı ifadeleri kullanın. PostgreSQL 16: WITH Sorguları, PostgreSQL 17: WITH Sorguları, PostgreSQL 17 Sürüm Notları

Repeatable Read, sıralı ifadelerin kardeş CTE’ler gibi davranmasını sağlamaz. İşlem denetimi dışındaki ilk ifadeyle oluşturulan işlem anlık görüntüsünü korur; ancak sonraki ifadeler yine işlemin kendi önceki yazma işlemlerini görür. Bu yalıtım düzeyini kullanan uygulamalar, serileştirme hatalarından sonra işlemleri yeniden denemeye de hazır olmalıdır. PostgreSQL: Repeatable Read Yalıtım Düzeyi

MATERIALIZED ve NOT MATERIALIZED, veri değiştiren CTE görünürlüğü için geçici çözüm sağlamaz. PostgreSQL, yan etkisiz olmayan CTE’lerde NOT MATERIALIZED seçeneğini yok sayar. Bu planlayıcı denetimleri, aynı satıra yönelik yazma işlemlerinin sırasını belirleyemez. PostgreSQL: SELECT

Döndürülen satırlar doğal olarak sonraki işlemin girdisini oluşturuyorsa veri değiştiren bir CTE seçin. Sonraki iş önceki tablo değişikliklerine veya uygulamanın vereceği bir karara ihtiyaç duyuyorsa sıralı ifadeler seçin. İsteklerin zamanlamasını iyileştirirken bu bağımlılığı koruyun ve birden fazla ifadenin birlikte tamamlanması gerektiğinde açık bir işlem kullanın.

Kaynaklar