سؤال

ما هي أفضل طريقة لإنشاء قيد غير فارغة في الخلية بحيث fieldA وfieldB لا يمكن أن يكون كل من NULL. لا يهمني إذا كان أي واحد هو فارغة في حد ذاته، فقط طالما أن مجال آخر له قيمة غير فارغة. وإذا كانت لديهما قيم غير فارغة، ثم انه من الافضل حتى.

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

المحلول

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

CREATE TABLE foo (
  FieldA INT,
  FieldB INT
);

DELIMITER //
CREATE TRIGGER InsertFieldABNotNull BEFORE INSERT ON foo
FOR EACH ROW BEGIN
  IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
    SIGNAL SQLSTATE '45000'
    SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null';
  END IF;
END//
CREATE TRIGGER UpdateFieldABNotNull BEFORE UPDATE ON foo
FOR EACH ROW BEGIN
  IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
    SIGNAL SQLSTATE '45000'
    SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null';
  END IF;
END//
DELIMITER ;

INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error
UPDATE foo SET FieldA = NULL; -- gives error

نصائح أخرى

وهذه ليست إجابة مباشرة على سؤالك، ولكن بعض المعلومات الإضافية.

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

COALESCE(a, b, c, d) IS NULL -- True if all are NULL

COALESCE(a, b, c, d) IS NOT NULL -- True if any one is not null

ويمكن استخدام هذا في المشغل الخاص بك.

وSklivvz: اختبار مع الخلية 5.0.51a، أجد أنه يوزع التحقق من القيد، ولكن لا تفرض عليه. يمكنني إدراج (NULL، NULL) مع عدم وجود خطأ. اختبرت كل MYISAM وك InnoDB. وفي وقت لاحق باستخدام إظهار CREATE TABLE يدل على أن التحقق من القيد غير موجود في تعريف الجدول، على الرغم من عدم إعطاء خطأ عند تعريف الجدول.

وهذا يتطابق مع الخلية دليل الذي يقول: "يتم تحليل شرط التحقق ولكن تجاهلها من قبل جميع محركات التخزين."

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

CREATE TABLE foo (
  FieldA INT,
  FieldB INT,
  FieldA_or_FieldB TINYINT NOT NULL;
);

DELIMITER //
CREATE TRIGGER FieldABNotNull BEFORE INSERT ON foo
FOR EACH ROW BEGIN
  IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
    SET NEW.FieldA_or_FieldB = NULL;
  ELSE
    SET NEW.FieldA_or_FieldB = 1;
  END IF;
END//

INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error

وأنت أيضا في حاجة إلى الزناد مماثلة من قبل UPDATE.

وهذه هي صيغة قياسية لمثل هذا القيد، ولكن الخلية يتجاهل بسعادة القيد بعد ذلك

ALTER TABLE `generic` 
ADD CONSTRAINT myConstraint 
CHECK (
  `FieldA` IS NOT NULL OR 
  `FieldB` IS NOT NULL
) 

ولقد فعلت شيئا من هذا القبيل في SQL Server، لست متأكدا ما اذا كانت ستعمل مباشرة في الخلية، ولكن:

ALTER TABLE tableName ADD CONSTRAINT constraintName CHECK ( (fieldA IS NOT NULL) OR (fieldB IS NOT NULL) );

وعلى الأقل أنا أعتقد أن هذا بناء الجملة.

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

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