خانه/ تغییر داده‌ها/ MERGE

MERGE: افزودن، به‌روزرسانی و حذف در یک عملیات

متوسط ۱۳ دقیقه مطالعه

در درس UPDATE، سناریویی دیدیم که یک جدول موقت (Staging) قیمت‌های تازه داشت و باید در جدول اصلی به‌روز می‌شدند. اما واقعیت این است که در دنیای واقعی، جدول Staging معمولاً هم محصولات جدید دارد (که باید INSERT شوند) هم محصولات موجود (که باید UPDATE شوند) — و نوشتن دو دستور جدا برای این دو حالت، هم تکراری است هم مستعد خطا. MERGE دقیقاً همین مشکل را حل می‌کند: افزودن، به‌روزرسانی (و حتی حذف) را در یک دستور واحد ترکیب می‌کند.

ساختار MERGE در SQL Server

sql
MERGE INTO Products AS target
USING StagingProducts AS source
ON target.Id = source.Id

WHEN MATCHED THEN
  UPDATE SET target.Price = source.Price

WHEN NOT MATCHED BY TARGET THEN
  INSERT (Id, Name, Price)
  VALUES (source.Id, source.Name, source.Price);

سه بخش اصلی این‌جا:

  • USING: منبع داده‌ی جدید (معمولاً یک جدول Staging یا یک زیرپرس‌وجو)
  • ON: شرط تطبیق بین جدول هدف و منبع (شبیه شرط JOIN)
  • WHEN MATCHED / WHEN NOT MATCHED BY TARGET: اگر تطبیق پیدا شد چه کاری انجام شود (معمولاً UPDATE)، و اگر پیدا نشد چه کاری (معمولاً INSERT)

می‌توان یک شاخه‌ی سوم هم اضافه کرد — WHEN NOT MATCHED BY SOURCE THEN DELETE — برای حذف ردیف‌هایی از جدول هدف که دیگر در منبع وجود ندارند.

مهم: MERGE کاملاً مخصوص SQL Server (و چند موتور دیگر مثل Oracle و PostgreSQL جدید) است. SQLite اصلاً چنین دستوری ندارد — اجرای مستقیم MERGE در این Playground با خطای نحوی متوقف می‌شود.

معادل SQLite: INSERT ... ON CONFLICT DO UPDATE

SQLite برای همان سناریوی رایج‌ترِ MERGE — «اگر بود به‌روز کن، اگر نبود اضافه کن» (که به آن Upsert هم می‌گویند) — یک نحو ساده‌تر دارد:

sql
INSERT INTO products (id, name, price)
VALUES (1, N'کیبورد', 1450000)
ON CONFLICT(id) DO UPDATE SET
  price = excluded.price;

یعنی: «سعی کن این ردیف را اضافه کنی؛ اگر به دلیل تکراری‌بودن id (که PRIMARY KEY است) با تعارض روبه‌رو شدی، به‌جایش قیمتش را به‌روز کن.» کلمه‌ی excluded به مقداری اشاره می‌کند که قرار بود درج شود ولی به‌خاطر تعارض، درج نشد. بیا این را روی دو حالت — یک محصول موجود و یک محصول تازه — امتحان کنیم:

امتحانش کن — Upsert با ON CONFLICT DO UPDATE
«کیبورد» (id=1) قیمتش به ۱۴۵۰۰۰۰ به‌روز شد — چون از قبل وجود داشت. «ماوس» (id=2) به‌عنوان ردیف کاملاً تازه اضافه شد. همین یک دستور، هم نقش INSERT را بازی کرد، هم نقش UPDATE را — دقیقاً همان ایده‌ی پشت MERGE.

MERGE کِی واقعاً به‌کار می‌آید؟

MERGE (یا معادل Upsert آن) بیشتر در این سناریوها ارزشش را نشان می‌دهد:

  • همگام‌سازی داده (Data Sync): وارد کردن دوره‌ای یک فایل یا جدول Staging به جدول اصلی، جایی که بعضی ردیف‌ها جدیدند و بعضی باید به‌روز شوند.
  • پردازش دسته‌ای (Batch Processing): وقتی چند صد یا چند هزار ردیف باید هم‌زمان بررسی و همگام شوند — یک MERGE به‌جای صدها INSERT/UPDATE جدا.
نکته‌ی عملی: برای یک Upsert ساده و تک‌ردیفی، معمولاً نوشتن مستقیم IF EXISTS ... UPDATE ELSE INSERT (یا همین ON CONFLICT در SQLite) خواناتر از یک MERGE کامل است. ارزش واقعی MERGE وقتی نمایان می‌شود که با حجم بالایی از ردیف‌ها، از یک منبع دیگر، هم‌زمان سروکار داری.

جمع‌بندی این درس (و کل فصل ۶)

  • MERGE در SQL Server، INSERT، UPDATE و DELETE را بر اساس تطبیق با یک منبع دیگر، در یک دستور ترکیب می‌کند.
  • SQLite دستور MERGE ندارد؛ معادل رایج‌ترین کاربردش (Upsert) با INSERT ... ON CONFLICT DO UPDATE پیاده می‌شود.
  • MERGE بیشتر برای همگام‌سازی حجم بالا از داده مناسب است، نه یک به‌روزرسانی ساده‌ی تک‌ردیفی.

با این درس، فصل ۶ (تغییر داده‌ها) کامل شد! تا این‌جا یاد گرفتی چطور داده بخوانی، فیلتر کنی، تجمیع کنی، بین جدول‌ها ارتباط برقرار کنی، و حالا چطور آن را تغییر بدهی. در فصل بعدی، یک قدم عقب‌تر می‌رویم و می‌بینیم چطور از اول، یک پایگاه‌داده‌ی خوب طراحی کنیم — نرمال‌سازی، مدل‌های ER و روابط.