سؤال

أرغب في الحصول على تشغيل لأداء التشغيل التالي للسجلات المدرجة:

 # pseudocode
 if new.group_id is null
    set new.group_id = new.id
 else
    # don't touch it
 end

أكثر وضوحا: قل لدي جدول واحد مع ثلاثة أعمدة: id المفتاح الأساسي، group_id int ، value varchar.

عندما أدخل مع group_id مثل هذا:

INSERT INTO table(value, group_id) VALUES ('a', 10)

اود الحصول على:

id | group_id | value
---+----------+------
 1 |       10 | a

لكن عندما أغفل group_id:

INSERT INTO table(value) VALUES ('b')

يجب ضبطه تلقائيًا على id من هذا السجل:

id | group_id | value
---+----------+------
 2 |        2 | b

هل هو ممكن مع الزناد؟ (أعلم أنه يمكنني تحديث السجل بعد الإدراج ولكن الحصول على الزناد سيكون أجمل.)

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

المحلول

لا أعرف بأي طريقة للقيام بذلك في بيان واحد ، حتى باستخدام الزناد.

حل الزناد الذي اقترحه lucky سيبدو هكذا في MySQL:

CREATE TRIGGER MyTrigger BEFORE INSERT ON MyTable
FOR EACH ROW BEGIN
  SET NEW.group_id = COALESCE(NEW.group_id, NEW.id);
END

ومع ذلك ، هناك مشكلة. في ال BEFORE INSERT المرحلة ، المولدة تلقائيا id لم يتم إنشاء القيمة بعد. حتى إذا group_id هو فارغ ، إنه افتراضي ل NEW.id وهو دائما 0.

ولكن إذا غيرت هذا الزناد إلى إطلاق النار أثناء AFTER INSERT المرحلة ، لذلك يمكنك الوصول إلى القيمة التي تم إنشاؤها من NEW.id, ، لا يمكنك تعديل قيم الأعمدة.

MySQL لا يدعم التعبيرات عن DEFAULT من عمود ، لذلك لا يمكنك إعلان هذا السلوك في تعريف الجدول أيضًا.

الحل الوحيد هو القيام INSERT, ، ثم قم على الفور UPDATE لتغيير ال group_id إذا لم يتم تعيينه.

INSERT INTO MyTable (group_id, value) VALUES (NULL, 'a');
UPDATE MyTable SET group_id = COALESCE(group_id, id) WHERE id = LAST_INSERT_ID();

نصائح أخرى

أنا أجيب هنا ، كما في الإجابة المقبولة بيل كاروين تنص على:

في مرحلة الإدراج قبل ، لم يتم إنشاء قيمة المعرف التي تم إنشاؤها تلقائيًا بعد. لذلك إذا كانت Group_ID خالية ، فهي تقتصر على new.id التي هي دائمًا 0.


لدي إجابة لذلك - بالنسبة للرجال (والزوار القادمين) ، إليك نقاط قليلة: لا يمكنك تحديث الجدول من حيث يتم استدعاء المشغل ، لأنه ستحصل خطأ 1442:

Error Code: 1442
Can't update table 'MyTable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

1. لتحديث الصف الجديديستخدم BEFORE INSERT ON الزناد ، وبهذه الطريقة يمكنك تحديث جميع الحقول للصف الجديد ، والتي يمكن الوصول إليها عبر مشغل جديد أي

set NEW.group_id = NEW.id

2.GET AUTO_INCREMENT قيمة قبل الإدراج:

SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='MyTable'

لتلخيص - Trigger SQL لـ 'd يكون شيئًا على النحو التالي:

DELIMITER //
DROP TRIGGER IF EXISTS MyTrigger//
CREATE TRIGGER MyTrigger BEFORE INSERT ON MyTable
FOR EACH ROW BEGIN
    IF new.group_id IS NULL
        set @auto_id := (SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES
                         WHERE TABLE_NAME='MyTable' AND TABLE_SCHEMA=DATABASE() ); 
        set NEW.group_id = @auto_id;
    ENF IF;
END;
//
DELIMITER ;

هذا يعمل بالنسبة لي

DELIMITER $$
CREATE TRIGGER `myTriggerNameHere`
BEFORE INSERT ON `table` FOR EACH ROW
BEGIN
    SET NEW.group_id = IF(NEW.group_id IS NULL, LAST_INSERT_ID()+1, NEW.group_id);
END;
$$
DELIMITER ;

أعتقد أن هذا سيعمل من أجلك

انا لدي طاولتان

test_b: a_id, value
test_c: a_id, value

وهنا مشغل على إدراج الاختبار ب. يتحقق لمعرفة ما إذا كان A_ID فارغًا وما إذا كان يدرج 0

CREATE TRIGGER test_b AFTER INSERT ON test_b
  FOR EACH ROW 
    INSERT INTO test_c (a_id, value) VALUES (IFNULL(NEW.a_id, 0),NEW.value)

يجب أن يفعل هذا الزناد ما طلبته.

   CREATE TRIGGER mytrigger BEFORE INSERT ON mytable
          IF new.group_id IS NULL
            SET new.group_id = new.id
          END IF
      END;

يتم نسخه من مثال مشابه جدًا في وثائق MySQL صفحة.

يبدو أن الزناد مبالغ فيه في هذا الموقف. ببساطة تطبيق الافتراضي.

CREATE TABLE `test` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `value` varchar(100) NOT NULL,
    `group_id` TINYINT(3) UNSIGNED NOT NULL DEFAULT '2'
)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top