Bir değeri olması gereken iki boş değer sütunu


10

Açıklama Yok Sorusu:

Yine de her zaman 1 değerinin olmasını gerektiren 2 null değerin bir kısıtlaması var mı? Örneğin, her ikisi de null olan ancak bir değere sahip olması gereken en az 1 değerine sahip iki tarih sütunu

Sorun Açıklaması:

Diyelim ki Gider denen masam var

ve 2 randevunuz var:

prevision_expense_expiration_date DATE NULLABLE expense_payment_date DATE NULLABLE

bu 2 sütunun mantığı şudur:

Bir şey satın aldım ve bunun için ödeme yapmam gerektiğini biliyorum, bir tarih, telefon faturası gibi. Bunu bir gider_ödeme_tarihi ile gider olarak gireceğim. Bu tarih, ödemem gereken varsayılan tarih, ancak faturanın son kullanma tarihi gibi ödemenin gerçek tarihi değil.

Başka bir durumda, hizmet için bazı sağlayıcıların hediye kartlarını satıyorum. Ben olabilir hizmet müvekkilime transfer benim sağlayıcıya satın alma gideri sadece istemci kartından yararlanmak eğer. Bu nedenle, hediye kartının bir son kullanma tarihi vardır, hediye kartının geçerli olduğu zaman için bir masraf olarak girmeden bu 'masraf' için bir ön şart yapmak istiyorum, hediye kartının süresi dolarsa, bu 'masraf' hesaba girmemelidir sistemi.

Ben prevision_expense ve teyit_expense denilen 2 eşit tablolar olabilir biliyorum ama ben aynı tablo, 2 tarih, nullable var, ama bir şey her zaman gerekli böylece kısıtlamak ya da bir şey var doğru gelmiyor.

Başka bir olası strateji daha var:

payment_date DATE NOT NULL is_prevision_date BOOL NOT NULL

Yani, bu durumda, eğer tarih prevision ise bool değeri 1, aksi takdirde 0 olacaktır. Null değer yok, hepsi iyi. dışında bir prevision tarih ve THEN (iki gün sonra diyelim) bu maliyet için onaylanmış bir tarih var, bu durumda stratejisi 2 ben bu seçeneği olmayacak onaylanmış bir tarih var.

Veritabanı tasarımında her şeyi yanlış mı yapıyorum? : D

Yanıtlar:


10

JD Schmidt'in cevabının bir sürümü, ancak fazladan bir sütunun garipliği olmadan:

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

2

SQL Server kullanıyorsanız, tablonuzda kalıcı bir hesaplanmış sütun kullanarak bir tetikleyici kullanmaktan kaçınabilirsiniz:

CREATE TABLE Test_Constraint
(
    A DateTime Null,
    B DateTime Null,
    A_and_B AS (CASE WHEN A IS Null AND B IS Null THEN Null ELSE Convert(Binary(1), 1) END) PERSISTED Not Null 
);

Hesaplanan A_and_B sütunundaki case deyimi, hem A hem de B sütunu null ise boş değer döndürür, ancak hesaplanan sütundaki Boş Değil kısıtlaması eki önleyen bir hata oluşturur. Aksi takdirde 1 döndürür.

Hesaplanan sütun kalıcı olduğundan, fiziksel olarak tabloda saklanacaktır. İkili dosyaya dönüştür, bunun etkisini en aza indirir ve sütunu 1 uzunluğundaki ikili veri türü yapar.


1
SQL Server'da bunu bir CHECKkısıtlamayla da yapabilirsiniz. Kalıcı sütuna gerek yok.
ypercubeᵀᴹ

1
Harika, bu biraz daha temiz görünüyor. CREATE TABLE Test_Constraint2 ( A DateTime Null, B DateTime Null, CONSTRAINT A_or_B_Not_Null CHECK (CASE WHEN A IS Null AND B IS Null THEN 0 ELSE 1 END = 1) )
Shane Estelle

mükemmel cevap! Bu diğerinden daha uygun ama MySQL kullandığım için, CHECK CLAUSE ayrıştırılmış ancak MySQL üzerinde yok sayılır, bu yüzden diğer yanıtı kabul edilen olarak işaretlerim. +1
Bart Calixto

1

Burada aynı şeylere benzeyen bir makale buldum

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//
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

teşekkürler, im MySQL kullanarak ve bu onunla mükemmel çalışıyor. özellikle null değil sütun hatası null bir değer atma nedeniyle.
Bart Calixto
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.