sql - এসকিউএল সার্ভারে ইনসার্ট বা আপডেটের জন্য সমাধান




sql-server database (14)

SQL সার্ভার 2008 এ আপনি MERGE বিবৃতিটি ব্যবহার করতে পারেন

MyTable(KEY, datafield1, datafield2...) একটি টেবিল গঠন অনুমান করুন MyTable(KEY, datafield1, datafield2...)

প্রায়শই আমি একটি বিদ্যমান রেকর্ড আপডেট করতে চাই, অথবা যদি এটি বিদ্যমান না থাকে তবে একটি নতুন রেকর্ড সন্নিবেশ করান।

মূলত:

IF (key exists)
  run update command
ELSE
  run insert command

এই লেখার সেরা উপায় কি?


UPDATE UP-NO-ROWS- আপডেট হলে INSERT রুট আপডেট করুন, কোনও জাতি শর্তটি রোধ করতে INSERT প্রথমটি বিবেচনা করুন (কোনও হস্তক্ষেপ মুছে ফেলা অনুমান করা হচ্ছে)

INSERT INTO MyTable (Key, FieldA)
   SELECT @Key, @FieldA
   WHERE NOT EXISTS
   (
       SELECT *
       FROM  MyTable
       WHERE Key = @Key
   )
IF @@ROWCOUNT = 0
BEGIN
   UPDATE MyTable
   SET FieldA[email protected]FieldA
   WHERE Key[email protected]Key
   IF @@ROWCOUNT = 0
   ... record was deleted, consider looping to re-run the INSERT, or RAISERROR ...
END

একটি জাতি শর্ত এড়িয়ে চলার পাশাপাশি, যদি বেশিরভাগ ক্ষেত্রেই রেকর্ড ইতিমধ্যে বিদ্যমান থাকে তবে এটি ইনপুটটি ব্যর্থ হতে পারে, CPU টি নষ্ট করে।

সম্ভবত SQL2008 এর জন্য অগ্রাধিকারযোগ্য MERGE ব্যবহার করে।


আপনি MERGE বিবৃতিটি ব্যবহার করতে পারেন, এই বিবৃতিটি যদি বিদ্যমান না থাকে তবে বিদ্যমান তথ্যটি সন্নিবেশ করার জন্য ব্যবহৃত হয় বা বিদ্যমান থাকে।

MERGE INTO Employee AS e
using EmployeeUpdate AS eu
ON e.EmployeeID = eu.EmployeeID`

আপনি এই প্রশ্নের ব্যবহার করতে পারেন। সব SQL সার্ভার সংস্করণে কাজ। এটা সহজ, এবং পরিষ্কার। কিন্তু আপনি 2 প্রশ্নের ব্যবহার প্রয়োজন। আপনি MERGE ব্যবহার করতে না পারেন, তাহলে আপনি ব্যবহার করতে পারেন

    BEGIN TRAN

    UPDATE table
    SET Id = @ID, Description = @Description
    WHERE Id = @Id

    INSERT INTO table(Id, Description)
    SELECT @Id, @Description
    WHERE NOT EXISTS (SELECT NULL FROM table WHERE Id = @Id)

    COMMIT TRAN

দ্রষ্টব্য: উত্তর নেতিবাচক ব্যাখ্যা করুন


আমি সমাধান নিচে চেষ্টা করেছিলাম এবং এটি আমার জন্য কাজ করে, যখন সন্নিবেশ বিবৃতি জন্য সমান্তরাল অনুরোধ ঘটে।

begin tran
if exists (select * from table with (updlock,serializable) where key = @key)
begin
   update table set ...
   where key = @key
end
else
begin
   insert table (key, ...)
   values (@key, ...)
end
commit tran

আমি সাধারণত এটির জন্য কয়েকটি পোস্টার আগেই বলেছি, এটি যাচাই করার জন্য এবং তারপরে সঠিক পথটি যা করছে তার জন্য আমি যা করি। এই কাজটি করার সময় আপনাকে মনে রাখতে হবে যে এসকিউএল দ্বারা ক্যাশে চালানো নির্বাহ পরিকল্পনাটি একটি পাথ বা অন্যের জন্য ননপোটিমাল হতে পারে। আমি বিশ্বাস করি এটি করার সর্বোত্তম উপায় দুটি ভিন্ন সঞ্চিত পদ্ধতিতে কল করা।

FirstSP:
If Exists
   Call SecondSP (UpdateProc)
Else
   Call ThirdSP (InsertProc)

এখন, আমি প্রায়ই আমার নিজের পরামর্শ অনুসরণ করি না, তাই এটি লবণের একটি শস্য নিয়ে নিন।



একটি নির্বাচন করুন, যদি আপনি ফলাফল পান তবে এটি আপডেট করুন, যদি না হয় তবে এটি তৈরি করুন।


যদি আপনি ADO.NET ব্যবহার করেন, ডেটা অ্যাডাপ্টার এটি পরিচালনা করে।

যদি আপনি এটি নিজে পরিচালনা করতে চান তবে এটি হল:

আপনার কী কলামে একটি প্রাথমিক কী সীমাবদ্ধতা নিশ্চিত করুন।

তারপর আপনি:

  1. আপডেট করুন
  2. যদি আপডেটটি ব্যর্থ হয় তবে কীটির সাথে একটি রেকর্ড ইতিমধ্যে বিদ্যমান থাকে, সন্নিবেশ করান। আপডেট ব্যর্থ না হলে, আপনি সমাপ্ত।

আপনি এটি অন্যভাবে রাউন্ড করতে পারেন, অর্থাৎ প্রথমে সন্নিবেশ করান এবং সন্নিবেশ ব্যর্থ হলে আপডেটটি করুন। সাধারণত প্রথম উপায় ভাল, কারণ ইনসেলার চেয়ে আপডেট প্রায়ই করা হয়।


যদি আপনি প্রথম কোনও সন্নিবেশের পরে কোনও আপডেটটি ব্যবহার করে থাকেন তবে জাতি শর্তগুলি কি আসলেই গুরুত্বপূর্ণ? আসুন আপনার দুটি থ্রেড আছে যা কী কীটির জন্য মান সেট করতে চান:

থ্রেড 1: মান = 1
থ্রেড 2: মান = 2

উদাহরণ জাতি শর্ত দৃশ্যকল্প

  1. কী সংজ্ঞায়িত করা হয় না
  2. থ্রেড 1 আপডেট সঙ্গে ব্যর্থ হয়
  3. থ্রেড 2 আপডেট সঙ্গে ব্যর্থ হয়
  4. সঠিকভাবে এক থ্রেড 1 বা থ্রেড 2 সন্নিবেশ সঙ্গে সফল। যেমন থ্রেড 1
  5. অন্যান্য থ্রেড সন্নিবেশ (ত্রুটি ডুপ্লিকেট কী সহ) সহ ব্যর্থ হয় - থ্রেড 2।

    • ফলাফল: সন্নিবেশ করা দুটি পদার্থের "প্রথম", মূল্য নির্ধারণ করে।
    • চেয়েছিলেন ফলাফল: তথ্য লেখার জন্য 2 টি থ্রেডের সর্বশেষ (আপডেট বা সন্নিবেশ) মূল্য নির্ধারণ করা উচিত

কিন্তু; বহুমুখী পরিবেশে, ওএস সময়সূচী থ্রেড এক্সিকিউশনের ক্রমকে সিদ্ধান্ত নেয় - উপরের দৃশ্যটিতে, যেখানে আমাদের এই রেসিডেন্সটি থাকে, তখন এটি OS গুলো কার্যকর করার ক্রম অনুসারে সিদ্ধান্ত নেয়। আই: এটা বলা ভুল যে "থ্রেড 1" বা "থ্রেড 2" একটি সিস্টেম দৃষ্টিভঙ্গি থেকে "প্রথম" ছিল।

যখন মৃত্যুদণ্ডের সময় থ্রেড 1 এবং থ্রেড 2 এর জন্য খুব ঘনিষ্ঠ হয়, তখন জাতি শর্তের ফলাফল কোন ব্যাপার না। একমাত্র প্রয়োজন থ্রেড এক ফলে মান নির্ধারণ করা উচিত।

বাস্তবায়ন করার জন্য: "ডুপ্লিকেট কী" ত্রুটির ফলাফল সন্নিবেশ করে আপডেটটি অনুসরণ করলে, এটি সফল হিসাবে বিবেচিত হবে।

এছাড়াও, অবশ্যই কোনও ডেটাবেসে মূল্যবোধটি মানতে হবে না যা আপনি লিখেছেন তার মান হিসাবে একই।


যদিও এটিতে বেশিরভাগ মন্তব্য করার জন্য আমি দেরী করছি MERGE ব্যবহার করে আরো একটি সম্পূর্ণ উদাহরণ যুক্ত করতে চাই।

যেমন সন্নিবেশ + আপডেট বিবৃতি সাধারণত "Upsert" বিবৃতি বলা হয় এবং SQL সার্ভারে MERGE ব্যবহার করে প্রয়োগ করা যেতে পারে।

এখানে একটি খুব ভাল উদাহরণ দেওয়া হয়েছে: weblogs.sqlteam.com/dang/archive/2009/01/31/… - weblogs.sqlteam.com/dang/archive/2009/01/31/…

উপরোক্ত লকিং এবং concurrency দৃশ্যকল্প পাশাপাশি ব্যাখ্যা।

আমি রেফারেন্সের জন্য একই উদ্ধৃত করা হবে:

ALTER PROCEDURE dbo.Merge_Foo2
      @ID int
AS

SET NOCOUNT, XACT_ABORT ON;

MERGE dbo.Foo2 WITH (HOLDLOCK) AS f
USING (SELECT @ID AS ID) AS new_foo
      ON f.ID = new_foo.ID
WHEN MATCHED THEN
    UPDATE
            SET f.UpdateSpid = @@SPID,
            UpdateTime = SYSDATETIME()
WHEN NOT MATCHED THEN
    INSERT
      (
            ID,
            InsertSpid,
            InsertTime
      )
    VALUES
      (
            new_foo.ID,
            @@SPID,
            SYSDATETIME()
      );

RETURN @@ERROR;

যে ব্যবহার প্যাটার্ন উপর নির্ভর করে। বিবরণে হারিয়ে যাওয়া ছাড়া বড় ছবিটি দেখার দরকার নেই। উদাহরণস্বরূপ, রেকর্ড তৈরি হওয়ার পরে ব্যবহারের প্যাটার্ন 99% আপডেট হয়, তাহলে 'ইউপিএসটিটি' সবচেয়ে ভাল সমাধান।

প্রথম সন্নিবেশ (আঘাত) পরে, এটি সমস্ত একক বিবৃতি আপডেট, no ifs বা buts হবে। সন্নিবেশের 'যেখানে' শর্তটি অন্যথায় এটি সদৃশ অন্তর্ভুক্ত করবে এবং আপনি লকিংয়ের সাথে মোকাবিলা করতে চাইবেন না।

UPDATE <tableName> SET <field>[email protected]field WHERE key[email protected]key;

IF @@ROWCOUNT = 0
BEGIN
   INSERT INTO <tableName> (field)
   SELECT @field
   WHERE NOT EXISTS (select * from tableName where key = @key);
END

একটি অনুরূপ পূর্ববর্তী প্রশ্নের আমার বিস্তারিত উত্তর দেখুন

@ বিউও ক্রাউফোর্ড এসকিউএল 2005 এবং এর নিচে একটি ভাল উপায়, যদিও আপনি যদি Rep প্রদান করেন তবে এটি SO কে প্রথম লোকের কাছে যেতে হবে । একমাত্র সমস্যা হলো প্রবেশের জন্য এটি এখনও দুটি আইও অপারেশন।

এমএস Sql2008 এসকিউএল থেকে merge প্রবর্তন: 2003 মান:

merge tablename with(HOLDLOCK) as target
using (values ('new value', 'different value'))
    as source (field1, field2)
    on target.idfield = 7
when matched then
    update
    set field1 = source.field1,
        field2 = source.field2,
        ...
when not matched then
    insert ( idfield, field1, field2, ... )
    values ( 7,  source.field1, source.field2, ... )

এখন এটি সত্যিই একটি আইও অপারেশন, কিন্তু ভয়ানক কোড :-(


/*
CREATE TABLE ApplicationsDesSocietes (
   id                   INT IDENTITY(0,1)    NOT NULL,
   applicationId        INT                  NOT NULL,
   societeId            INT                  NOT NULL,
   suppression          BIT                  NULL,
   CONSTRAINT PK_APPLICATIONSDESSOCIETES PRIMARY KEY (id)
)
GO
--*/

DECLARE @applicationId INT = 81, @societeId INT = 43, @suppression BIT = 0

MERGE dbo.ApplicationsDesSocietes WITH (HOLDLOCK) AS target
--set the SOURCE table one row
USING (VALUES (@applicationId, @societeId, @suppression))
    AS source (applicationId, societeId, suppression)
    --here goes the ON join condition
    ON target.applicationId = source.applicationId and target.societeId = source.societeId
WHEN MATCHED THEN
    UPDATE
    --place your list of SET here
    SET target.suppression = source.suppression
WHEN NOT MATCHED THEN
    --insert a new line with the SOURCE table one row
    INSERT (applicationId, societeId, suppression)
    VALUES (source.applicationId, source.societeId, source.suppression);
GO

আপনার প্রয়োজন যাই হোক না কেন টেবিল এবং ক্ষেত্রের নাম প্রতিস্থাপন করুন। ব্যবহার শর্তে যত্ন নিন। তারপর DECLARE লাইনের ভেরিয়েবলগুলির জন্য উপযুক্ত মান (এবং টাইপ) সেট করুন।

চিয়ার্স।






upsert