2009-11-02 28 views
6

Tek bir tablonun (üyeler) sütununa başvurmak istediğim 4 tablo (atanan, sınıf, seçilmiş, durum) var. 4 tablonun değerleri, tarih tablosuna dayanan zamana duyarlı (members_history). İstenen sonuç, sorgunun tüm üyeleri ve geçerli atanan konumu veya üyeler sırasındaki geçerli seçilmiş pozisyonu, sınıfı ve statüyü vermesi ve yabancı satırlardan elde edilen ek bilgileri içermesidir.Dinamik Yabancı Anahtarlar - Nasıl Uygulanır?

Bunun yerine sadece döndükten sonra:

id, kullanıcı adı, parola, tuz, name_last, name_first, & date_leave date_join;

sorgu dönecekti

id, kullanıcı adı, parola, tuz, name_prefix, name_last, name_first, hours_extra, date_join, date_leave, appointed, class, elected & status;

Eklenen bir sütunun geçmişte geçerli bir değeri yoksa nerede sonuç NULL olmalıdır.

Şimdi bunu alt-querys ile yapabileceğimi düşünüyorum, ancak kafamı klavyeye karşı çarpıttım. Daha sonra başka bir vuruş yapacağım, ama o zamana kadar, kimse bir şut vermeye mi, yoksa doğru yöne bakmaya mı çalışıyor?

şöyle benim SQL (hayır cinas) tablo yapısı şöyledir: Sonunda

CREATE TABLE IF NOT EXISTS `members` (
`id` mediumint(3) unsigned NOT NULL auto_increment COMMENT 'Members Unique Id', 
`username` varchar(32) collate utf8_bin NOT NULL COMMENT 'Mebers Username', 
`password` varchar(64) collate utf8_bin NOT NULL COMMENT 'Members Password Hash', 
`salt` varchar(32) collate utf8_bin NOT NULL COMMENT 'Members Password Salt', 
`name_first` varchar(32) collate utf8_bin NOT NULL COMMENT 'Members First Name', 
`name_last` varchar(32) collate utf8_bin NOT NULL COMMENT 'Members Last Name', 
`date_join` date NOT NULL COMMENT 'Members Join Date', 
`date_leave` date default NULL COMMENT 'Members Resgination Date (If Applicable)', 
PRIMARY KEY (`id`), 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Members id in this table = mid in other tables'; 

CREATE TABLE IF NOT EXISTS `members:apointed` (
`id` tinyint(3) unsigned NOT NULL auto_increment COMMENT 'Unique value', 
`name_prefix` varchar(8) collate utf8_bin NOT NULL COMMENT 'Prefix Added to Members Name', 
`hours_extra` decimal(4,2) NOT NULL COMMENT 'Hours Given as Bonus for Holding this Position.', 
`position` varchar(40) collate utf8_bin NOT NULL COMMENT 'Name of the Posisiton', 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Undefined within the SOP or By-Laws.'; 

CREATE TABLE IF NOT EXISTS `members:class` (
`id` tinyint(3) unsigned NOT NULL auto_increment COMMENT 'Unique Id', 
`class` varchar(8) collate utf8_bin NOT NULL COMMENT 'Unique Value', 
PRIMARY KEY (`id`), 
UNIQUE KEY `value` (`class`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Article I, Section 1 Subsection B: Classes of Membership'; 

CREATE TABLE IF NOT EXISTS `members:elected` (
`id` tinyint(3) unsigned NOT NULL auto_increment COMMENT 'Unique value', 
`name_prefix` varchar(8) collate utf8_bin NOT NULL COMMENT 'Prefix Added to Members Name', 
`hours_extra` decimal(4,2) NOT NULL COMMENT 'Hours Given as Bonus for Holding this Position.', 
`position` varchar(40) collate utf8_bin NOT NULL COMMENT 'Name of the Posisiton', 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Article II'; 

CREATE TABLE IF NOT EXISTS `members:status` (
`id` tinyint(3) unsigned NOT NULL auto_increment COMMENT 'Bit''s Place', 
`status` varchar(16) collate utf8_bin NOT NULL COMMENT 'Categorie''s Name', 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Article I, Section 1, Subsection A: Categories of Membership'; 

CREATE TABLE IF NOT EXISTS `members_history` (
`id` int(10) unsigned NOT NULL auto_increment COMMENT 'Unique Id', 
`mid` tinyint(3) unsigned NOT NULL COMMENT 'Members Unique Id.', 
`table` enum('class','elected','appointed','status') NOT NULL COMMENT 'Name of Table that was Edited.', 
`value` tinyint(3) unsigned NOT NULL COMMENT 'Value', 
`start` date NOT NULL COMMENT 'Value''s Effect Date', 
`end` date default NULL COMMENT 'Value''s Expiration Date', 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Member History'; 

members_history.mid, her üye üzerlerinde geçmişi üyeleri tabloda kimliği için bir FK (ancak Hepsi de, her üyenin bir sınıfa ve statüye sahip olması gerekecek. members_history.value, members:{members_history.table}.id için bir FK'dir;

INSERT INTO `members` 
(`id`, `username`, `password`, `salt`, `name_first`, `name_last`, `date_join`, `date_join`) VALUES 
( 1, 'Dygear',MD5('pass'), 's417',  'Mark', 'Tomlin',  DATE(), NULL), 
( 2, 'uberusr',MD5('p455'), '235f',  'Howard', 'Singer',  DATE(), NULL), 
( 3,'kingchief',MD5('leet'), '32fs','Christopher', 'Buckham',  DATE(), NULL); 

INSERT INTO `members:apointed` 
(`id`, `name_prefix`, `hours_extra`, `posisiton`) VALUES 
( 1,   '',   0.00, 'Crew Chief'), 
( 2,   '',   20.00, 'Engineer'), 
( 3,   'Lt.',   40.00, 'Lieutenant'), 
( 4,  'Capt.',   60.00, 'Captin'), 
( 5,  'Chief.',   80.00, '3rd Assistant Chief of Operation'); 

INSERT INTO `members:class` 
(`id`, `class`) VALUES 
( 1, 'Class I'), 
( 2, 'Class II'); 

INSERT INTO `members:elected` 
(`id`, `name_prefix`, `hours_extra`, `posisiton`) VALUES 
( 1,   '',   40.00, 'Trustee'), 
( 2,   '',   40.00, 'Chairman of the Board'), 
( 3,  'Prez.',   40.00, 'President'), 
( 4,  'VPrez.',   40.00, 'Vice-President'), 
( 5,   '',   40.00, 'Recording Secretary'), 
( 6,   '',   40.00, 'Service Secretary'), 
( 7,   '',   40.00, 'Corresponding Secretary'), 
( 8,   '',   40.00, 'Financial Secretary Treasuer'), 
( 9,   '',   40.00, 'Assistant Financial Secretary Treasuer'), 
( 10,  'Chief.',   80.00, 'Chief of Operations'), 
( 11,  'Chief.',   80.00, 'First Deputy Chief of Operations'), 
( 12,  'Chief.',   80.00, 'Second Deputy Chief of Operation'); 

INSERT INTO `members:status` 
(`id`, `status`) VALUES 
( 1, 'Active'), 
( 2, 'Inactive'), 
( 3, 'Student'), 
( 4, 'Probationary'), 
( 5, 'Lifetime'), 
( 6, 'Cadet'), 
( 7, 'Honorary'), 
( 8, 'Medical'), 
( 9, 'Military'), 
( 10, 'Resigned'), 
( 11, 'Disvowed'); 


INSERT INTO `members_history` 
(`id`, `mid`, `table`, `value`, `start`, `end`) VALUES 
(NULL,  1, 'apointed',  3, DATE(), NULL), 
(NULL,  1, 'class',  1, DATE(), NULL), 
(NULL,  1, 'status',  1, DATE(), NULL), 
(NULL,  2, 'elected',  4, DATE(), NULL), 
(NULL,  2, 'class',  1, DATE(), NULL), 
(NULL,  2, 'status',  1, DATE(), NULL), 
(NULL,  3, 'apointed',  10, DATE(), '2010-05-01'), 
(NULL,  3, 'class',  1, DATE(), NULL), 
(NULL,  3, 'status',  1, DATE(), NULL); 

cevap

11

polimorfik dernekler adlı bir tasarım kullanıyorsunuz ve genellikle yanlış yapılmış. İşe yaraması için yolu başka tablo oluşturmak için, members:abstract ki: tüm üyelerinize tabloları niteliklerini için

CREATE TABLE IF NOT EXISTS `members:abstract` (
`id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, 
`type` enum('class','elected','appointed','status') NOT NULL, 
    UNIQUE KEY (`id`, `type`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 

Bu tablo ana tablo olarak hizmet vermektedir. Bu tabloların her biri, birincil anahtarını, kimlik değerlerini otomatik olarak oluşturmaz, ancak members:abstract'un birincil anahtarını başvuruyorsa, birincil anahtarını olarak değiştirir. Ben sadece members:appointed göstereceğim ama diğerleri benzer olacaktır.

CREATE TABLE IF NOT EXISTS `members:appointed` (
`id` INT UNSIGNED NOT NULL PRIMARY KEY, -- not auto_increment 
`name_prefix` varchar(8) collate utf8_bin NOT NULL COMMENT 'Prefix Added to Members Name', 
`hours_extra` decimal(4,2) NOT NULL COMMENT 'Hours Given as Bonus for Holding this Position.', 
`position` varchar(40) collate utf8_bin NOT NULL COMMENT 'Name of the Posisiton', 
FOREIGN KEY (`id`) REFERENCES `members:abstract` (`id`) ON DELETE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Undefined within the SOP or By-Laws.'; 

Bir tetikleyici ile otomatik olarak bu tablo kazanç otomatik oluşturulan değerler yapabilirsiniz:

DELIMITER // 
DROP TRIGGER IF EXISTS ins_appointed// 
CREATE TRIGGER ins_appointed BEFORE INSERT ON `members:appointed` 
FOR EACH ROW BEGIN 
    INSERT INTO `members:abstract` (`type`) VALUES ('appointed'); 
    SET NEW.id = LAST_INSERT_ID(); 
END; // 
DELIMITER ; 

diğer özellik tabloları her biri için de yapın.

Kimlik değerlerinin artık tüm öznitelik tablolarınızda benzersiz olduğunu unutmayın.

Bir sonraki members_history numaralı yabancı anahtarın hedefini members:abstract yapın. Bu tablo yabancı anahtar tanımlar

CREATE TABLE IF NOT EXISTS `members_history` (
`id` INT unsigned NOT NULL auto_increment COMMENT 'Unique Id', 
`mid` INT unsigned NOT NULL COMMENT 'Members Unique Id.', 
`value` INT UNSIGNED NOT NULL, 
`table` enum('class','elected','appointed','status') NOT NULL, 
`start` date NOT NULL COMMENT 'Value''s Effect Date', 
`end` date default NULL COMMENT 'Value''s Expiration Date', 
PRIMARY KEY (`id`), 
FOREIGN KEY (`mid`) REFERENCES `members` (`id`) ON DELETE CASCADE, 
FOREIGN KEY (`value`, `table`) REFERENCES `members:abstract` (`id`, `type`) ON DELETE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Member History'; 

Bildirim böylece olamaz referans members:abstract özniteliğin yanlış türde bir kimliği.

Şimdi referans bütünlüğü ve tüm başvurulan özellik tabloları ortak ebeveyn olmadan polimorfik dernek uygulamaya çalıştığınızda imkansız tutarlılık güvenebilirsiniz. Ben orijinal yayına olası değerleri hakkında bazı ayrıntı ekledik

SELECT m.username, 
    m.password, m.salt, m.name_first, m.name_last, 
    MAX(a.name_prefix) AS name_prefix, 
    COALESCE(MAX(a.hours_extra), MAX(e.hours_extra)) AS hours_extra, 
    MAX(m.date_join) AS date_join, 
    MAX(m.date_leave) AS date_leave, 
    MAX(a.position) AS appointed, 
    MAX(c.class) AS class, 
    MAX(e.position) AS elected, 
    MAX(s.status) AS status 
FROM `members` m 
JOIN `members_history` h ON (h.mid = m.id) 
LEFT OUTER JOIN `members:appointed` a ON (h.table = 'appointed' AND h.value = a.id) 
LEFT OUTER JOIN `members:class` c ON (h.table = 'class' AND h.value = c.id) 
LEFT OUTER JOIN `members:elected` e ON (h.table = 'elected' AND h.value = e.id) 
LEFT OUTER JOIN `members:status` s ON (h.table = 'status' AND h.value = s.id) 
GROUP BY m.id; 
+0

Üstün yanıt Bill, çok teşekkür ederim. Bundan çok şey öğrendim. –

+0

Görünüşe göre 'tetikleyici' kullandığım üretim sunucumdaki gücüm içinde değil. Git ha huh. –

+0

Tetik oldukça basit, sadece iki deyim uzun. Tablolarınızdan birine her eklediğinizde uygulama kodunuza eşdeğer bir şey yapabilirsiniz. –

1

tek ihtiyacınız bir sol dış geçmişi türlerinin her biri ve ne olursa olsun mantığı siz "geçerli" satırı almak gerekir için katılmak olduğunu.

Tablo yapınız sizin için bir örnek hazırlamak için bana yeterince mantıklı gelmiyor. belki ONE örnek üyesine ve ONE özniteliği için birkaç satırlık tarih girerseniz, size yardımcı olabilirim.

+0

:

İşte (MySQL 5.1.40 üzerinde test) Eğer açıklanan sonuç döndürür sorgu var. –

+0

Teşekkürler. şimdi fatura'nın cevabına bakın lütfen. – longneck

İlgili konular