سؤال

لقد كتبت المخزنة proc من شأنها أن تفعل التحديث إذا كان السجل موجودا ، وإلا فإنه سوف تفعل إدراج.يبدو شيئا من هذا القبيل:

update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)

بلدي المنطق وراء الكتابة في هذا الطريق هو أن التحديث سوف تؤدي ضمنيا حدد باستخدام where وإذا بإرجاع 0 ثم إدراج سوف تأخذ مكان.

البديل القيام بهذه الطريقة سيكون للقيام حدد ثم استنادا إلى عدد الصفوف التي يتم إرجاعها إما تحديث أو إدراج.هذه لا تعتبر غير فعالة لأنه إذا كنت تفعل التحديث سوف يسبب 2 يختار (أول صريحة حدد مكالمة والثانية ضمنية في حيث التحديث).إذا كان بروك كانت تفعل إدراج ثم لن يكون هناك فرق في الكفاءة.

هو صوت المنطق هنا ؟ هذا كيف يمكنك أن الجمع بين insert و update في تخزين بروك?

هل كانت مفيدة؟

المحلول

توليكم هو الحق ، وهذا هو أفضل طريقة للقيام بذلك و هذا يسمى upsert/دمج.

أهمية UPSERT - من sqlservercentral.com:

كل تحديث في الحالة المذكورة أعلاه نحن إزالة واحد قراءة إضافية من الجدول إذا كنا استخدام UPSERT بدلا من موجود.للأسف إدراج ، سواء UPSERT و إذا كان موجود أساليب استخدام نفس العدد من يقرأ على الطاولة.وبالتالي التحقق من وجود ينبغي أن يتم إلا عندما يكون هناك جدا وجيها يبرر إضافية I/O.الأمثل طريقة تفعل الأشياء هو التأكد من أن كنت والقليل يقرأ ممكن على DB.

أفضل استراتيجية هي أن تحاول تحديث.إذا لم الصفوف المتأثرة تحديث ثم إدراج.في معظم الظروف صف بالفعل وجود واحد فقط I/O سيكون المطلوبة.

تحرير:يرجى مراجعة هذا الجواب و بلوق وظيفة مرتبطة للتعرف على مشاكل مع هذا النمط و كيفية جعلها تعمل آمنة.

نصائح أخرى

يرجى قراءة على مدونتي جيدة وآمنة نمط يمكنك استخدام.هناك الكثير من الاعتبارات ، و قبلت الجواب على هذا السؤال بعيد عن آمنة.

للحصول على إجابة سريعة محاولة النمط التالي.وسوف تعمل بشكل جيد على SQL 2000 وما فوق.SQL 2005 يعطيك معالجة الخطأ الذي يفتح خيارات أخرى و SQL 2008 يمنحك دمج الأوامر.

begin tran
   update t with (serializable)
   set hitCount = hitCount + 1
   where pk = @id
   if @@rowcount = 0
   begin
      insert t (pk, hitCount)
      values (@id,1)
   end
commit tran

إذا كان ليتم استخدامها مع SQL Server 2000/2005 رمز الأصلي يحتاج إلى المغلقة في المعاملات للتأكد من أن البيانات تبقى ثابتة في المتزامنة السيناريو.

BEGIN TRANSACTION Upsert
update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)
COMMIT TRANSACTION Upsert

هذا وسوف إضافية في أداء التكاليف ، ولكن يضمن سلامة البيانات.

إضافة كما اقترح دمج ينبغي أن تستخدم حيثما كان ذلك متاحا.

دمج هي واحدة من الميزات الجديدة في SQL Server 2008 بالمناسبة.

أنت لا تحتاج فقط إلى تشغيله في الصفقة ، كما يجب عزل عالية المستوى.أنا الواقع الافتراضي مستوى العزل قراءة ارتكبت هذه المدونة تحتاج قابل للتسلسل.

SET transaction isolation level SERIALIZABLE
BEGIN TRANSACTION Upsert
UPDATE myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
  begin
    INSERT into myTable (ID, Col1, Col2) values (@ID @col1, @col2)
  end
COMMIT TRANSACTION Upsert

ربما أيضا إضافة @@خطأ التحقق التراجع يمكن أن تكون فكرة جيدة.

إذا كنت لا تفعل دمج في SQL server 2008 يجب تغيير إلى:

إذا @@rowcount = 0 @@خطأ=0

وإلا إذا كان التحديث يفشل لسبب ما وبعد ذلك سوف نحاول أن تضاف بعد ذلك لأن rowcount على فشل البيان 0

مروحة كبيرة من UPSERT حقا التخفيضات على رمز لإدارة.هنا هو طريقة أخرى لا تفعل ذلك:واحدة من معلمات الإدخال هو معرف إذا كان المعرف هو باطل أو 0, كنت أعلم أنه إدراج وإلا التحديث.يفترض تطبيق يعرف إذا كان هناك معرف ، لذلك لن تعمل في جميع الحالات, ولكن قطع ينفذ في النصف إذا كنت تفعل.

المنطق الخاص بك يبدو الصوت ، ولكن قد ترغب في النظر في إضافة بعض التعليمات البرمجية لمنع إدراج إذا كنت قد مرت في محدد أساسي.

وإلا إذا كنت دائما تفعل إدراج إذا كان التحديث لم تؤثر على أي من سجلات ماذا يحدث عندما يقوم شخص ما حذف سجل قبل "UPSERT" أشواط ؟ الآن سجل كنت تحاول التحديث غير موجود, لذلك سوف إنشاء سجل بدلا من ذلك.التي ربما ليست السلوك الذي كنت تبحث عنه.

تعديل ديما مالينكو بعد:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 

BEGIN TRANSACTION UPSERT 

UPDATE MYTABLE 
SET    COL1 = @col1, 
       COL2 = @col2 
WHERE  ID = @ID 

IF @@rowcount = 0 
  BEGIN 
      INSERT INTO MYTABLE 
                  (ID, 
                   COL1, 
                   COL2) 
      VALUES      (@ID, 
                   @col1, 
                   @col2) 
  END 

IF @@Error > 0 
  BEGIN 
      INSERT INTO MYERRORTABLE 
                  (ID, 
                   COL1, 
                   COL2) 
      VALUES      (@ID, 
                   @col1, 
                   @col2) 
  END 

COMMIT TRANSACTION UPSERT 

يمكنك فخ الخطأ وإرسال السجل إلى فشل إدراج جدول.
كنت بحاجة للقيام بذلك لأننا اتخاذ أية بيانات ترسل عبر WSDL وإذا أمكن تحديد ذلك داخليا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top