লক্ষ্য সারণির একটি উপসেট মার্জ করুন


71

আমি MERGEএকটি টেবিল থেকে সারি সন্নিবেশ করানো বা মুছতে একটি বিবৃতি ব্যবহার করার চেষ্টা করছি , তবে আমি কেবল এই সারিগুলির একটি উপসেটে কাজ করতে চাই। এর জন্য ডকুমেন্টেশনের MERGEএকটি বেশ দৃ strongly়ভাবে শব্দযুক্ত সতর্কতা রয়েছে:

লক্ষ্য সারণী থেকে কেবলমাত্র কলামগুলিই মিলানোর উদ্দেশ্যে ব্যবহৃত হয় তা নির্দিষ্ট করা গুরুত্বপূর্ণ। এটি, উত্স সারণীর সংশ্লিষ্ট কলামের সাথে তুলনা করা যায় এমন লক্ষ্য সারণী থেকে কলামগুলি নির্দিষ্ট করুন। অন ​​ক্লজে লক্ষ্য টেবিলের মধ্যে সারিগুলি ফিল্টার করে ক্যোয়ারি পারফরম্যান্সকে উন্নত করার চেষ্টা করবেন না, যেমন নির্দিষ্ট করে এবং টার্গেট_টিবিল.কম = মান উল্লেখ না করে। এটি করা অপ্রত্যাশিত এবং ভুল ফলাফল ফিরে আসতে পারে।

তবে এটি আমার MERGEকাজটি করার জন্য আমাকে যা করতে হবে তা হ'ল ।

আমার কাছে থাকা ডেটা হ'ল স্ট্যান্ডার্ড বহু থেকে বহুগুলিতে আইটেমের বিভাগগুলিতে যোগ হওয়া টেবিল (যেমন কোন আইটেমগুলি কোন বিভাগে অন্তর্ভুক্ত করা হয়) এর মত:

CategoryId   ItemId
==========   ======
1            1
1            2
1            3
2            1
2            3
3            5
3            6
4            5

আমার যা করা দরকার তা হ'ল আইটেমগুলির একটি নতুন তালিকা সহ একটি নির্দিষ্ট বিভাগের সমস্ত সারি কার্যকরভাবে প্রতিস্থাপন করা। এটি করার আমার প্রাথমিক প্রয়াসটি এরকম দেখাচ্ছে:

MERGE INTO CategoryItem AS TARGET
USING (
  SELECT ItemId FROM SomeExternalDataSource WHERE CategoryId = 2
) AS SOURCE
ON SOURCE.ItemId = TARGET.ItemId AND TARGET.CategoryId = 2
WHEN NOT MATCHED BY TARGET THEN
    INSERT ( CategoryId, ItemId )
    VALUES ( 2, ItemId )
WHEN NOT MATCHED BY SOURCE AND TARGET.CategoryId = 2 THEN
    DELETE ;

এটি আমার পরীক্ষাগুলিতে কাজ করছে বলে মনে হয় তবে এমএসডিএন আমাকে স্পষ্টভাবে সতর্ক করে না বলে আমি করছি। এটি আমাকে উদ্বিগ্ন করে তুলেছে যে আমি পরে অপ্রত্যাশিত সমস্যার মধ্যে চলে যাব, তবে MERGEনির্দিষ্ট ক্ষেত্রের মান ( CategoryId = 2) সহ আমার কেবলমাত্র সারিগুলিকে প্রভাবিত করার জন্য এবং অন্যান্য বিভাগ থেকে সারিগুলি উপেক্ষা করার জন্য আমি অন্য কোনও উপায় দেখতে পাচ্ছি না ।

এই একই ফলাফল অর্জন করার জন্য "আরও সঠিক" উপায় আছে কি? এবং এমএসডিএন আমাকে "অপ্রত্যাশিত বা ভুল ফলাফল" সম্পর্কে সতর্ক করছে?


হ্যাঁ, ডকুমেন্টেশনটি যদি "অপ্রত্যাশিত এবং ভুল ফলাফল" এর একটি দৃ .় উদাহরণ থাকে তবে এটি আরও কার্যকর হবে।
একে

3
@ অ্যালেক্সকুজনেসভ এখানে একটি উদাহরণ রয়েছে
পল হোয়াইট

@ এসকিউএলকিউই লিঙ্কটির জন্য আপনাকে ধন্যবাদ - আইএমও ডকুমেন্টেশনটি যদি মূল পৃষ্ঠা থেকে উল্লেখ করা হয় তবে এটি আরও ভাল হবে।
একে

1
@ অ্যালেক্সকুজনেসভ সম্মত হয়েছেন। দুর্ভাগ্যক্রমে, 2012-এর জন্য বিওএল পুনর্গঠনটি অন্যান্য অনেক বিষয়ের মধ্যে তা ভেঙে দিয়েছে। এটি 2008 আর 2 ডকুমেন্টেশনে বেশ সুন্দরভাবে যুক্ত ছিল linked
পল হোয়াইট

উত্তর:


103

MERGEবিবৃতি একটি জটিল বাক্য গঠন এবং একটি এমনকি আরো জটিল বাস্তবায়ন আছে, কিন্তু মূলত ধারণা দুই টেবিল যোগদানের জন্য, সারি পরিবর্তন করা (সন্নিবেশিত, আপডেট, বা মুছে ফেলা হয়েছে) প্রয়োজন ফিল্টার করুন, এবং তারপর অনুরোধ পরিবর্তন সম্পাদন করতে। নিম্নলিখিত নমুনা তথ্য দেওয়া:

DECLARE @CategoryItem AS TABLE
(
    CategoryId  integer NOT NULL,
    ItemId      integer NOT NULL,

    PRIMARY KEY (CategoryId, ItemId),
    UNIQUE (ItemId, CategoryId)
);

DECLARE @DataSource AS TABLE
(
    CategoryId  integer NOT NULL,
    ItemId      integer NOT NULL

    PRIMARY KEY (CategoryId, ItemId)
);

INSERT @CategoryItem
    (CategoryId, ItemId)
VALUES
    (1, 1),
    (1, 2),
    (1, 3),
    (2, 1),
    (2, 3),
    (3, 5),
    (3, 6),
    (4, 5);

INSERT @DataSource
    (CategoryId, ItemId)
VALUES
    (2, 2);

লক্ষ্য

╔════════════╦════════╗
 CategoryId  ItemId 
╠════════════╬════════╣
          1       1 
          2       1 
          1       2 
          1       3 
          2       3 
          3       5 
          4       5 
          3       6 
╚════════════╩════════╝

উৎস

╔════════════╦════════╗
 CategoryId  ItemId 
╠════════════╬════════╣
          2       2 
╚════════════╩════════╝

কাঙ্ক্ষিত ফলাফলটি হ'ল উত্স থেকে প্রাপ্ত ডেটা সহ লক্ষ্যমাত্রায় ডেটা প্রতিস্থাপন করা, তবে কেবল তার জন্য CategoryId = 2MERGEউপরের বর্ণনার বিবরণ অনুসরণ করে , আমাদের এমন একটি ক্যোয়ারী লেখা উচিত যা উত্সটিতে যোগ দেয় এবং কেবল কীগুলিতে লক্ষ্য রেখে যায় এবং কেবলমাত্র WHENক্লজগুলিতে সারিগুলি ফিল্টার করে:

MERGE INTO @CategoryItem AS TARGET
USING @DataSource AS SOURCE ON 
    SOURCE.ItemId = TARGET.ItemId 
    AND SOURCE.CategoryId = TARGET.CategoryId
WHEN NOT MATCHED BY SOURCE 
    AND TARGET.CategoryId = 2 
    THEN DELETE
WHEN NOT MATCHED BY TARGET 
    AND SOURCE.CategoryId = 2 
    THEN INSERT (CategoryId, ItemId)
        VALUES (CategoryId, ItemId)
OUTPUT 
    $ACTION, 
    ISNULL(INSERTED.CategoryId, DELETED.CategoryId) AS CategoryId,
    ISNULL(INSERTED.ItemId, DELETED.ItemId) AS ItemId
;

এটি নিম্নলিখিত ফলাফল দেয়:

╔═════════╦════════════╦════════╗
 $ACTION  CategoryId  ItemId 
╠═════════╬════════════╬════════╣
 DELETE            2       1 
 INSERT            2       2 
 DELETE            2       3 
╚═════════╩════════════╩════════╝
╔════════════╦════════╗
 CategoryId  ItemId 
╠════════════╬════════╣
          1       1 
          1       2 
          1       3 
          2       2 
          3       5 
          3       6 
          4       5 
╚════════════╩════════╝

কার্যকর করার পরিকল্পনাটি হ'ল: পরিকল্পনাটি মার্জ করুন

উভয় টেবিল সম্পূর্ণ স্ক্যান করা আছে লক্ষ্য করুন। আমরা এই অদক্ষ মনে করতে পারি, কারণ কেবল সারি যেখানে CategoryId = 2লক্ষ্য সারণীতে প্রভাবিত হবে। এখানেই বুকস অনলাইনে সতর্কতা আসে the লক্ষ্যমাত্রায় কেবল প্রয়োজনীয় সারিগুলিকে স্পর্শ করতে অনুকূলিত করার একটি বিভ্রান্ত প্রচেষ্টা:

MERGE INTO @CategoryItem AS TARGET
USING 
(
    SELECT CategoryId, ItemId
    FROM @DataSource AS ds 
    WHERE CategoryId = 2
) AS SOURCE ON
    SOURCE.ItemId = TARGET.ItemId
    AND TARGET.CategoryId = 2
WHEN NOT MATCHED BY TARGET THEN
    INSERT (CategoryId, ItemId)
    VALUES (CategoryId, ItemId)
WHEN NOT MATCHED BY SOURCE THEN
    DELETE
OUTPUT 
    $ACTION, 
    ISNULL(INSERTED.CategoryId, DELETED.CategoryId) AS CategoryId,
    ISNULL(INSERTED.ItemId, DELETED.ItemId) AS ItemId
;

ধারাটিতে যুক্তি যুক্ত হওয়ার ONঅংশ হিসাবে প্রয়োগ করা হয়। এই ক্ষেত্রে, যোগদানটি সম্পূর্ণ বাইরের যোগদান ( কেন এই পুস্তকাগুলি অনলাইন এন্ট্রি দেখুন )। বাহ্যিক যোগদানের অংশ হিসাবে লক্ষ্য সারিগুলিতে 2 বিভাগের জন্য চেক প্রয়োগ করার ফলে শেষ পর্যন্ত সারিগুলিতে আলাদা মান মুছে ফেলা হয় (কারণ তারা উত্সটির সাথে মেলে না):

╔═════════╦════════════╦════════╗
 $ACTION  CategoryId  ItemId 
╠═════════╬════════════╬════════╣
 DELETE            1       1 
 DELETE            1       2 
 DELETE            1       3 
 DELETE            2       1 
 INSERT            2       2 
 DELETE            2       3 
 DELETE            3       5 
 DELETE            3       6 
 DELETE            4       5 
╚═════════╩════════════╩════════╝

╔════════════╦════════╗
 CategoryId  ItemId 
╠════════════╬════════╣
          2       2 
╚════════════╩════════╝

মূল কারণটি হ'ল কারণটিতে ONঅনুচ্ছেদগুলিতে নির্দিষ্ট করা থাকলে তার চেয়ে বাহ্যিক সংযুক্তি দফায় ভিন্ন আচরণ করার পূর্বাভাস দেয় WHEREMERGEসিনট্যাক্স (এবং বাস্তবায়ন যোগদানের ক্লজ নিদিষ্ট উপর নির্ভর করে) শুধু এটা কঠিন দেখতে এই তাই তা নিশ্চিত করুন।

বই অনলাইন নির্দেশিকা (ইন সম্প্রসারিত অপ্টিমাইজ পারফরমেন্স এন্ট্রি) হেদায়েত যে সঠিক শব্দার্থিক নিশ্চিত করবে ব্যবহার প্রকাশ করা হয় উপলব্ধ করা হয় MERGE, বাক্য গঠন ব্যবহারকারী অগত্যা সব বাস্তবায়ন বিবরণ, অথবা উপায়ে অপটিমাইজার বৈধভাবে নতুন করে সাজানো হতে পারে জন্য অ্যাকাউন্ট বুঝতে না করেও কার্য সম্পাদনের দক্ষতার কারণে জিনিসগুলি।

প্রারম্ভিক ফিল্টারিং প্রয়োগের জন্য ডকুমেন্টেশনটি তিনটি সম্ভাব্য উপায় সরবরাহ করে:

একটি ফিল্টারিং শর্ত নির্দিষ্ট করা WHENদফা সঠিক ফলাফল গ্যারান্টী বা নিশ্চয়তা দিচ্ছে, কিন্তু এর অর্থ হতে পারে আরো সারি পড়া হয় এবং সোর্স এবং টার্গেট টেবিল থেকে প্রক্রিয়াজাত থেকে যথাযথভাবে বাধ্যতামূলক (হিসাবে প্রথম উদাহরণে দেখা)।

একটি দৃশ্য মাধ্যমে আপডেট করা হচ্ছে যে ফিল্টারিং শর্ত এছাড়াও রয়েছে সঠিক ফলাফল গ্যারান্টী বা নিশ্চয়তা দিচ্ছে (যেহেতু পরিবর্তিত সারি দৃশ্য মাধ্যমে আপডেটের জন্য প্রবেশযোগ্য হতে হবে) কিন্তু এই ডেডিকেটেড দৃশ্য প্রয়োজন নেই এবং এক যে মতামত আপডেট করার জন্য বিজোড় অবস্থার অনুসরণ করে।

একটি সাধারণ টেবিল এক্সপ্রেশন ব্যবহার ক্লজটিতে পূর্বাভাস যুক্ত করার অনুরূপ ঝুঁকি বহন করে ON, তবে কিছুটা ভিন্ন কারণে। অনেক ক্ষেত্রে এটি নিরাপদ হবে, তবে এটির (এবং বিস্তৃত ব্যবহারিক পরীক্ষার) বিষয়টি নিশ্চিত করার জন্য এটি কার্যকর করার পরিকল্পনার বিশেষজ্ঞ বিশ্লেষণের প্রয়োজন। উদাহরণ স্বরূপ:

WITH TARGET AS 
(
    SELECT * 
    FROM @CategoryItem
    WHERE CategoryId = 2
)
MERGE INTO TARGET
USING 
(
    SELECT CategoryId, ItemId
    FROM @DataSource
    WHERE CategoryId = 2
) AS SOURCE ON
    SOURCE.ItemId = TARGET.ItemId
    AND SOURCE.CategoryId = TARGET.CategoryId
WHEN NOT MATCHED BY TARGET THEN
    INSERT (CategoryId, ItemId)
    VALUES (CategoryId, ItemId)
WHEN NOT MATCHED BY SOURCE THEN
    DELETE
OUTPUT 
    $ACTION, 
    ISNULL(INSERTED.CategoryId, DELETED.CategoryId) AS CategoryId,
    ISNULL(INSERTED.ItemId, DELETED.ItemId) AS ItemId
;

এটি আরও অনুকূল পরিকল্পনার সাথে সঠিক ফলাফলগুলি পুনরাবৃত্তি করে না:

মার্জ পরিকল্পনা 2

পরিকল্পনাটি কেবলমাত্র সারণী থেকে 2 বিভাগের সারিগুলি পড়বে। লক্ষ্য সারণী বড় হলে এটি একটি গুরুত্বপূর্ণ পারফরম্যান্স বিবেচনা হতে পারে তবে MERGEসিনট্যাক্স ব্যবহার করে ভুলটি পাওয়া খুব সহজ ।

কখনও কখনও, MERGEপৃথক ডিএমএল ক্রিয়াকলাপ হিসাবে এটি লেখা আরও সহজ । এই পদ্ধতির একটি একক চেয়ে আরও ভাল অভিনয় করতে পারে MERGE, একটি ঘটনা যা প্রায়শই মানুষকে অবাক করে।

DELETE ci
FROM @CategoryItem AS ci
WHERE ci.CategoryId = 2
AND NOT EXISTS 
(
    SELECT 1 
    FROM @DataSource AS ds 
    WHERE 
        ds.ItemId = ci.ItemId
        AND ds.CategoryId = ci.CategoryId
);

INSERT @CategoryItem
SELECT 
    ds.CategoryId, 
    ds.ItemId
FROM @DataSource AS ds
WHERE
    ds.CategoryId = 2;

আমি জানি এটি একটি সত্যই পুরানো প্রশ্ন ... তবে "সাধারণ টেবিলের অভিব্যক্তিটি ব্যবহার করা ওএন ক্লজটিতে পূর্বাভাস যুক্ত করার ক্ষেত্রে একই রকম ঝুঁকি বহন করে, তবে কিছুটা ভিন্ন কারণে।" আমি জানি বিওএল এরও একইভাবে অস্পষ্ট সতর্কতা রয়েছে "" এই পদ্ধতিটি অন ক্লজে অতিরিক্ত অনুসন্ধানের মানদণ্ড নির্দিষ্ট করার অনুরূপ এবং ভুল ফলাফলও পেতে পারে। আমরা আপনাকে এই পদ্ধতিটি ব্যবহার এড়াতে পরামর্শ দিচ্ছি ... "। সিটিই পদ্ধতিটি আমার ব্যবহারের কেস সমাধান করার জন্য উপস্থিত হয়, তবে আমি ভাবছি এমন কোনও পরিস্থিতি বিবেচনা করছি না কিনা।
হেনরি লি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.