使用SQL模拟松散的“基于文档的”模式

时间:2011-12-20 13:37:58

标签: sql

我正在考虑使用SQL软件来存储和查询具有松散架构的对象。

我们知道一个对象对应一个SQL表的一行,它的属性对应于列。通过“松散模式”,我的意思是一个对象可以具有不与表格(而非表格)结构硬连线的属性。可以将任意(属性,值)附加到对象。


让我举一个具体的例子说明:

对于给定的对象:

<subject>
name:data structures
tag:CS 
description:easy
desired_seniority:5.0

<subject>
name:microprocessors
tag:CS,electronics        <multi-valued
description:easy
desired_seniority:5.5     <numeric

<teacher>
name:John Doe
tag:electronics
seniority:5.8

查询将是

For each teacher, 
return all subjects whose tags match and 
whose desired seniority is less than or equal to the teacher's

教师'John Doe'将与主题'微处理器'匹配,因为他们共享标签'electronics'和他的资历< em> 5.8 大于受试者所需的资历 5.5

请注意,我在字符串中使用了数字(查询进行比较)和多值(查询在'匹配中)'字符串。


究竟是什么:我正在寻找合适的数据模型和相应的查询,让我可以模拟SQL软件上的松散架构。


我接受这些限制:

  1. 教师和主题可能由 distinct
  2. 描述
  3. 属性会有一对一的对应关系(如果查询使用属性'x',则所有行都具有相同类型的属性'x1'和'x2')

  4. 我看到了http://www.igvita.com/2010/03/01/schema-free-mysql-vs-nosql/https://github.com/jamesgolick/friendly


    是的,有NoSQL数据库和特殊的ORM。我们使用Solr(太棒了!)。但是我会通过包含它们来避免增加项目的复杂性。模拟noSQL存储的性能开销不是问题。

1 个答案:

答案 0 :(得分:2)

在MySql中我会使用这样的东西:

CREATE TABLE IF NOT EXISTS `subject` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `description` varchar(255) NOT NULL,
  `desired_seniority` decimal(5,2) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;


INSERT INTO `subject` (`id`, `name`, `description`, `desired_seniority`) VALUES
(1, 'data structures', 'easy', 5.00),
(2, 'microprocesors', 'easy', 5.50);

CREATE TABLE IF NOT EXISTS `subject_tag` (
  `subject_id` int(10) unsigned NOT NULL,
  `tag_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`subject_id`,`tag_id`),
  KEY `fk_subject_tag_tags` (`tag_id`),
  KEY `fk_subject_tag_subject` (`subject_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `subject_tag` (`subject_id`, `tag_id`) VALUES
(1, 1),
(2, 1),
(2, 2);

CREATE TABLE IF NOT EXISTS `tag` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;


INSERT INTO `tag` (`id`, `name`) VALUES
(1, 'CS'),
(2, 'Electronics');


CREATE TABLE IF NOT EXISTS `teacher` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `surname` varchar(50) NOT NULL,
  `seniority` decimal(5,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;


INSERT INTO `teacher` (`id`, `name`, `surname`, `seniority`) VALUES
(1, 'John', 'Doe', 5.80),
(2, 'John', 'Brown', 5.30);



CREATE TABLE IF NOT EXISTS `teacher_tag` (
  `teacher_id` int(10) unsigned NOT NULL,
  `tag_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`teacher_id`,`tag_id`),
  KEY `fk_teacher_tag_tag1` (`tag_id`),
  KEY `fk_teacher_tag_teacher` (`teacher_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `teacher_tag` (`teacher_id`, `tag_id`) VALUES
(1, 2);


ALTER TABLE `subject_tag`
  ADD CONSTRAINT `fk_subject_tag_tag` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `fk_subject_tag_subject` FOREIGN KEY (`subject_id`) REFERENCES `subject` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

ALTER TABLE `teacher_tag`
  ADD CONSTRAINT `fk_teacher_tag_tag` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `fk_teacher_tag_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

为教师提供匹配的主题:

SELECT t.surname, t.name, GROUP_CONCAT( s.name SEPARATOR ' | ' ) AS subject_name
FROM teacher t
JOIN teacher_tag tt ON tt.teacher_id = t.id
JOIN subject_tag st ON st.tag_id = tt.tag_id
JOIN subject s ON st.subject_id = s.id
AND s.desired_seniority <= t.seniority
GROUP BY t.id