سؤال

لدي 4 طاولات (مجهزة، فئة، منتخبة، حالة أريد أن أقول المرجع إلى عمود جدول واحد (أعضاء). قيم الجداول 4 هي حساسة لحالة الوقت بناء على جدول السجل (الأعضاء_أعضاء). والنتيجة المرجوة هي أن الاستعلام يجب إخراج جميع الأعضاء والوضع الحالي المعين أو الموضع الحالي المنتخب الحالي، والطبق، والحالة داخل صف الأعضاء ويشمل معلومات إضافية تم الحصول عليها من الصفوف الأجنبية.

لذلك بدلا من العودة فقط:

معرف، اسم المستخدم، كلمة المرور، الملح، name_first، name_last، date_join & date_leave؛

سوف يعود الاستعلام

معرف، اسم المستخدم، كلمة المرور، الملح، name_prefix, ، name_first، name_last، hours_extra, ، date_join، date_leave، appointed, class, elected & status;

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

الآن أعتقد أنني أستطيع القيام بذلك مع الاستعلام الفرعي، ولكن كانت ضجيج رأسي حتى الآن ضد لوحة المفاتيح. سآخذ تأرجح آخر في وقت لاحق، ولكن حتى ذلك الحين، أي شخص آخر يرغب في إعطائها لقطة، أو محاولة توجيه لي في الاتجاه الصحيح؟

هي بنية الجداول الخاصة بي (لا المقصود منها) SQL (بدون تورية) على النحو التالي:

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 هو FK للحصول على معرف في طاولة الأعضاء، وليس كل عضو سيكون له تاريخ عليهم (ولكن في نهاية المطاف سيكونون جميعا، لأن كل عضو سيتعين عليه الحصول على فئة وحالة). members_history.value هو fk ل members:{members_history.table}.id;

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);
هل كانت مفيدة؟

المحلول

أنت تستخدم تصميم يسمى الجمعيات متعددة الأشكال وغالبا ما تفعل الخطأ. الطريقة لجعلها تعمل هي إنشاء جدول آخر، قل members:abstract:

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;

يعمل هذا الجدول كجدول أصل لجميع أعضائه. كل من هذه الجداول يغير مفتاحه الأساسي ليس توليد قيم المعرف تلقائيا، ولكن بدلا من ذلك مرجع المفتاح الأساسي members:abstract. وبعد سأعرض فقط members:appointed لكن الآخرين سيكونون مماثلة.

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.';

يمكنك جعل هذا الجدول يكتسب القيم الناتجة تلقائيا تلقائيا مع الزناد:

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 ;

افعل نفس الشيء لكل من جداول السمة الأخرى.

لاحظ أن قيم المعرف هي الآن فريدة من نوعها عبر جميع جداول السمة الخاصة بك.

بعد ذلك members:abstract الهدف لمفتاح أجنبي في members_history.

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';

لاحظ أن هذا الجدول يحدد مفتاح أجنبي بحيث أنت لا مراجع معرف النوع الخطأ من السمة في members:abstract.

الآن يمكنك الاعتماد على التكامل المرجعي و التناسق وهو أمر مستحيل عند محاولة تنفيذ الجمعيات متعددة الأعمدة دون الوالد المشترك لجميع جداول السمة المشار إليها.

إليك الاستعلام الذي يرجع النتيجة التي وصفها (تم اختبارها على MySQL 5.1.40):

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;

نصائح أخرى

كل ما تحتاجه هو الانضمام الخارجي الأيسر لكل نوع من أنواع التاريخ وأي شيء منطق تحتاج إلى اختيار الصف "الحالي".

بنية الجدول الخاصة بك لا تجعل من المنطقي كافية لي لوضع عينة لك. ربما إذا قمت بتوفير عضو عينة واحد واثنين من صفوف التاريخ لسمة واحدة، يمكنني مساعدتك.

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