MySQL Trigger لتحديث حقل إلى قيمة الهوية
سؤال
أرغب في الحصول على تشغيل لأداء التشغيل التالي للسجلات المدرجة:
# 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'
)