سؤال

في تنظيف هذه الإجابة تعلمت قليلا عن TRIGGERs والإجراءات المخزنة في الخلية، ولكن صدمت أنه في حين BEFORE INSERT وBEFORE UPDATE مشغلات يمكن تعديل البيانات، فإنها على ما يبدو لا يمكن أن يؤدي إدراج / تحديث فشل (أي التحقق من صحة). في هذه الحالة بالذات وكنت قادرا على الحصول على هذا العمل عن طريق التلاعب في البيانات في مثل هذه الطريقة من شأنها أن تسبب نسخة مكررة المفتاح الأساسي، وهو في هذه الحالة بالذات من المنطقي، ولكن لا يجعل بالضرورة معنى في الشعور العام.

هل هذا النوع من وظائف محتمل في الخلية؟ في أي RDBMS أخرى (تجربتي يقتصر على الخلية للأسف)؟ ولعل جملة أسلوب THROW EXCEPTION؟

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

المحلول

ومن هذا <وأ href = "https://web.archive.org/web/20180330233216/http://www.brokenbuild.com/blog/2006/08/15/mysql-triggers-how-do- أولا إحباط-على-إدراج التحديث، أو حذف-مع-الزناد / "يختلط =" نوفولو noreferrer "> بلوق وظيفة

<اقتباس فقرة>   

والخلية النوابض: كيف إجهاض على INSERT، UPDATE أو DELETE مع   اثار؟ على شخص #mysql EfNet ل   سأل:

     

كيف أقوم بإجراء الزناد إحباط العملية اذا فشلت بلدي قاعدة العمل؟

     

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

     

SP 11. هل الصحة والصحة النباتية لديها "رفع" بيان إلى "رفع أخطاء التطبيق"؟ عذرا، لا في الوقت الحاضر. وSIGNAL مستوى SQL والبيانات RESIGNAL هي على TODO.

     

وربما الخلية 5.2 ستشمل SIGNAL   بيان الأمر الذي سيجعل هذا الإختراق   سرقت مباشرة من الخلية مخزنة   برمجة الداخلي عفا عليها الزمن. ماذا   هو الإختراق؟ وأنت تسير لاجبار   الخلية في محاولة لاستخدام عمود   غير موجود. البشع؟ نعم. يفعل   عمل؟ بالتأكيد.

CREATE TRIGGER mytabletriggerexample
BEFORE INSERT
FOR EACH ROW BEGIN
IF(NEW.important_value) < (fancy * dancy * calculation) THEN
    DECLARE dummy INT;

    SELECT Your meaningful error message goes here INTO dummy 
        FROM mytable
      WHERE mytable.id=new.id
END IF; END;

نصائح أخرى

وهنا هو الطريقة التي فعلت ذلك. لاحظ SET NEW='some error';. الخلية سوف اقول لكم "المتغير 'الجديد' لا يمكن لتعيين قيمة 'خطأ: لا يمكن حذف هذا البند هناك سجلات في الجدول المبيعات مع هذا البند".

ويمكنك فخ هذا في التعليمات البرمجية ومن ثم تظهر الخطأ الناتج:)

DELIMITER $$
DROP TRIGGER IF EXISTS before_tblinventoryexceptionreasons_delete $$
CREATE TRIGGER before_tblinventoryexceptionreasons_delete
BEFORE DELETE ON tblinventoryexceptionreasons
FOR EACH ROW BEGIN
  IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblinventoryexceptionreasons = old.idtblinventoryexceptionreasons) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory exception reasons table with this item.';
  END IF;
END$$
DELIMITER ;

DELIMITER $$
DROP TRIGGER IF EXISTS before_storesalesconfig_delete $$
CREATE TRIGGER before_storesalesconfig_delete
BEFORE DELETE ON tblstoresalesconfig
FOR EACH ROW BEGIN
  IF (SELECT COUNT(*) FROM tblstoresales WHERE tblstoresales.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the sales table with this item.';
  END IF;
  IF (SELECT COUNT(*) FROM tblinventory WHERE tblinventory.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory table with this item.';
  END IF;
  IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory exceptions table with this item.';
  END IF;
  IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
  END IF;
END$$
DELIMITER ;

DELIMITER $$
DROP TRIGGER IF EXISTS before_tblinvoice_delete $$
CREATE TRIGGER before_tblinvoice_delete
BEFORE DELETE ON tblinvoice
FOR EACH ROW BEGIN
  IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblinvoice = old.idtblinvoice) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
  END IF;
END$$
DELIMITER ;

ولأن هذه المادة تأتي نحو الأعلى عندما كنت ابحث عن معالجة في الخلية يؤدي الخطأ، اعتقدت أن أشاطركم بعض المعرفة.

إذا كان هناك خطأ، يمكنك فرض الخلية لاستخدام <لأ href = "http://dev.mysql.com/doc/refman/5.5/en/signal.html" يختلط = "نوفولو" عنوان = "SIGNAL"> SIGNAL ، ولكن إذا لم تقم بتحديد أنها فئة كما SQLEXCEPTION، ثم شيئا لن يحدث، حيث تعتبر ليست كل SQLSTATEs سيئة، وحتى ذلك الحين كنت ديك للتأكد من أن <ل أ href = "http://dev.mysql.com/doc/refman/5.5/en/resignal.html" يختلط = "نوفولو" عنوان = "RESIGNAL"> RESIGNAL إذا لديك أي تداخل BEGIN كتل / END .

وبدلا من ذلك، وأبسط ربما لا تزال، في المشغل الخاص بك، أن يعلن معالج الخروج وresignal الاستثناء.

CREATE TRIGGER `my_table_AINS` AFTER INSERT ON `my_table` FOR EACH ROW
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
        RESIGNAL;
    DECLARE EXIT HANDLER FOR SQLWARNING
        RESIGNAL;
    DECLARE EXIT HANDLER FOR NOT FOUND
        RESIGNAL; 
    -- Do the work of the trigger.
END

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

وهذا يعمل مع النسخة 5.5 + أي شيء.

وهذا سيتم إحباط INSERT عن طريق رفع استثناء (من HTTP: // www.experts-exchange.com/Database/MySQL/Q_23788965.html )

DROP PROCEDURE IF EXISTS `MyRaiseError`$$

CREATE PROCEDURE `MyRaiseError`(msg VARCHAR(62))
BEGIN
DECLARE Tmsg VARCHAR(80);
SET Tmsg = msg;
IF (CHAR_LENGTH(TRIM(Tmsg)) = 0 OR Tmsg IS NULL) THEN
SET Tmsg = 'ERROR GENERADO';
END IF;
SET Tmsg = CONCAT('@@MyError', Tmsg, '@@MyError');
SET @MyError = CONCAT('INSERT INTO', Tmsg);
PREPARE stmt FROM @MyError;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$

والاستعمال:

call MyRaiseError('Here error message!');

والعمل Doen't في المشغلات (لا سمح الديناميكي SQL في وظيفة المخزنة أو المشغل)

ويمكنني استخدام الحل قذرة جدا:

وIf NEW.test=1 then CALL TEST_CANNOT_BE_SET_TO_1; end if;

عند يلقي اختبار = 1 ماي الاستثناء التالي:

وإجراءات administratie.TEST_CANNOT_BE_SET_TO_1 غير موجود

وليس تطورا ولكن بسرعة ومفيدة.

وفي MS SQL هل يمكن أن تجعل من العمل باستخدام بناء الجملة الصحيح:

IF UPDATE(column_name)
BEGIN
  RAISEERROR
  ROLLBACK TRAN
  RETURN
END

http://msdn.microsoft.com/en-us/magazine /cc164047.aspx

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