SQL多表和多列选择

时间:2014-01-28 21:47:49

标签: php mysql sql sql-server

我正在创建一个mysql数据库,该数据库为学校中的每个学生都有一个表,然后在每个表中都有每个学生的时间表。我需要能够运行一个脚本来搜索数据库中的每个表,每个列搜索2个值。例如,它需要搜索教师“x”的所有表和列,其中day_week = MondayA。在表格中,总共有11列,一个用于day_week,然后是5个用于期间课程(所以第1期课程,第2期课程等),然后另外5个用于每个期间的教师。

非常感谢任何帮助。

感谢。

4 个答案:

答案 0 :(得分:3)

首先,值得注意的是,这可能不是最佳方法。每个学生的一张桌子听起来像个坏主意。您将生成大量动态查询而无法利用索引,因此性能将受到影响。我强烈建议找到一种方法将表格分成一个表格,将时间序列变成连接表格。或者看一下noSQL(非关系方法)。文档数据库似乎可能适合这里。

那就是说,回答你的问题:你需要查询模式(information_schema表)以获取表和列的列表,然后循环查询表。

mysql docs here on information_schema

开始

答案 1 :(得分:3)

修复您的架构

首先,您的架构听起来非常糟糕。每次你添加一个新学生,你必须改变它(添加一个新的表),如果这是一个真正的学校,这将是一个绝对的灾难!更改模式比简单地将行插入表中更加昂贵,如果您的Web应用程序可以直接更改数据库,那么任何可能暴露的安全漏洞都可能导致人们在没有意识到的情况下弄乱您的表。

最重要的是,它会让学生查询绝对的痛苦。理想情况下,您的数据应该以一种方式进行布局,以便您回答可能曾经拥有的任何和所有问题。不仅仅是你现在的问题,还有未来的问题。

如果这还不够糟糕,它会让人质疑噩梦。您必须以某种方式跟踪表的数量及其名称,以便每次查询信息时它都运行完全不同的查询。一些查询,例如“去年加入的学生列表”,随着学生列表(表格数量)的增长而增加了大小,复杂性和时间。这可能是您已经遇到的问题,尽管很难从您的问题中简单地说出来。

正常化

简单地说,规范化很好地设计了架构'。这是一个模糊的话题,但它分为不同的层次;每个级别都取决于最后一个级别。

说实话,我并不理解不同层次的措辞,而且我自己在数据库中有点新意,但这里有正常化的要点,从我和#39已被教导:

每个值都意味着一个小而简单的东西

基本上,不要发疯,把一堆东西放在一个栏目中。设置一个类似于' Categories'的列是一个糟糕的设计,并且该值为长字符串,其内容类似于"Programming, Databases, Web Development, MySQL, Cows"

首先,解析字符串非常耗时,尤其是时间越长,其次,如果这些类别与其他任何类别相关联 - 例如,您可能有一个类别表供人们选择 - 那么现在您正在检查较大的字符串以查找较小字符串的内容。如果你想提取某个类别的每个项目,你将把该字符串与整个数据库进行匹配......这可能会非常缓慢。

我不确定这是否是规范化的一部分,但我学会做的是制作一个数字ID'我在多个表中引用的所有内容。例如,我不是拥有列'Name', 'Address', 'Birthday'的数据库表,而是'ID', 'Name', 'Address', 'Birthday'。 ID将是每行的唯一编号,即主键,如果在任何时候我想引用其中的任何人,我只是使用该编号。

数字比较/匹配要快得多,查找起来要快得多,而且整体数据库处理起来要好得多,并且让你创建的查询运行时间非常短,就像字符串一样 - 基于数据库。

要完成该示例,您可以拥有三个表;比如,' Articles',' Categories',' Article_Categories'。

' Articles'将保留所有实际文章及其属性。类似于'ID', 'Title', 'Content'

' Categories'将使用' ID' Category'来保留所有可用的类别。和' Article_Categories'字段。

' Article_ID'将文章组合分类; ' Category_ID'的独特组合和' Article_Categories'。

这可能是什么样的:

  • 文章
    • 1,' Web Cow Geniuses' Cows已被证明知道如何使用MySQL为网站创建出色的数据库。';
    • 2,'为什么要使用MySQL',"它是免费的,呃!";
  • 分类
    • 1,Cows;
    • 2,数据库;
    • 3,MySQL;
    • 4,编程;
    • 5,Web开发;
  • Article_Categories
    • 1,1;
    • 1,2;
    • 1,3;
    • 1,4;
    • 1,5;
    • 2,2;
    • 2,3;

请注意' People'中的每个组合是独特的;你永远不会看到,例如,' 1,3'两次。但是' 1'多次出现在第一列,' 3'多次出现在第二列。

这被称为“多对多”'表。当您在两个数据集之间存在关系时使用它,其中有多个组合用于混合它们。基本上,一个项目中的任意数量的项目可以对应于另一个项目中的任意数量的项目。

不要混合数据和元数据

基本上,数据是表格的内容。行内的值。元数据就是表格本身;表名,值类型以及两组不同数据之间的关系。

数据中的元数据

以下是将元数据放入数据的示例:

  • A' isStudent'表格列为' isTeacher'和' People'。

当数据放入' 'ID', 'Name', 'yes', 'yes''时,您可能会有一行他们既是教师又是学生,因此您可以添加People之类的内容。这听起来并不糟糕,可能有一位老师在同一所学校上课,所以有可能。

但是,它占用更多空间,因为你必须在两个列中都有某种值,即使它们只是一个或另一个。

更好的方法是将其拆分为三个单独的表:

  • A' Students'具有ID,姓名和每个人拥有的其他数据的表。
  • A' People.ID'仅使用' Teachers'的值的表格作为数据。
  • A' People.ID'仅使用' Students'的值的表格作为数据。

通过这种方式,学生的所有人都可以在Teachers'中被引用,并且所有教师都会在&{39; ID中被引用#39 ;.如前所述,我们使用' Classes'因为它可以更快地匹配表格。现在,只有尽可能多的教师参考,学生也是如此。这最初会占用更多的空间,因为将它们作为单独的表进行大小开销,但随着数据库的增长,这已经弥补了这一点。

这也允许您直接引用教师。假设您有一张' Classes'的表格,您只希望教师能够成为教师。您的Teachers'表,在' Teachers.ID'列,可以有一个' Mens_Products'的外键。这样,如果学生攻击数据库并试图以某种方式将自己作为教学课程,那么他们就不可能这样做。

元数据中的数据

这与您似乎遇到问题的情况非常相似。

数据本质上是我们想要存储的内容。学生姓名,教师姓名,两者的时间表等。但是,有时我们会将数据(如学生的姓名)放在元数据中 - 例如表格的名称。

每当您看到自己定期添加或更改数据库的架构时,将数据置于元数据中是一个巨大的迹象。在您的情况下,每个拥有自己的表的学生基本上都将他们的名字放在元数据中。

现在,有些时候你有点想要这样做,因为表的数量通常不会改变。它可以使事情更简单..例如,如果你有一个销售内衣的网站,你可能同时拥有' Womens_Products'和' Product_Categories'表。显然这个整理者' neater'解决方案是拥有一个' Trans_Products'表格,如果您想为两性都添加变性产品或其他销售产品,但在这种情况下, 并不重要。添加&{39} Birthday'并不难。表格,它不像你经常添加新表格。

不要重复数据

起初,这听起来像是我与我所说的一切相矛盾的。 "如果我不想复制数据,我应该如何在任何地方复制这些ID?!"但是,唉,这不完全是我的意思。事实上,这是为您可能引用的每个项目分别设置ID的另一个原因!

基本上,您不希望更新超出您需要的数据。例如,如果您有一个' Students'您的&{39; Teachers'中的列和你的People'上面例子中的表格,你有一个同时是学生教师的人,突然他们的生日被记录在两个不同的地方!现在,如果生日是错的,你想改变它怎么办?您必须更改两次

相反,你把它放在你的Student_Classes'表。这样,对于每个人来说,它只存在一次。

这似乎是一个明显的例子,但你会惊讶于它偶然发生的频率。请注意,并注意任何需要您在两个不同位置更新相同值的内容。

查询

所以,尽管如此,你应该如何查询?你应该使用什么类型的SELECT语句?

假设您有以下架构(主键为粗体):

  • 人:
    • ID
    • 名称(唯一)
    • 生日
  • 教师:
    • People_ID (外国:People.ID)
  • 生:
    • People_ID (外国:People.ID)
  • 类:
    • ID
    • 名称(唯一)
    • Teacher_ID(外语:Teachers.ID)
  • Class_Times:
    • Class_ID (外国:Classes.ID)
    • (枚举:'星期一','星期二','星期三','星期四', '星期五','星期六')
    • START_TIME
  • Student_Classes:
    • Student_ID (外国人:Students.ID)
    • Class_ID (外国:Classes.ID)

首先请注意' Class_ID'有两个主键...这使得两个唯一的组合,而不是单独的。如前所述,这使它成为多对多表。我也是为了{' Day'和' SELECT People.Name FROM People LEFT JOIN Teachers ON People.ID = Teachers.People_ID LEFT JOIN Classes ON People.ID = Classes.Teacher_ID LEFT JOIN Class_Times: ON Classes.ID = Class_Times.Class_ID WHERE Class_Times.Day = 'Monday'; '所以你不能在同一天上课两次。

另外,我们在星期几使用枚举可能会很糟糕...如果我们想要添加星期日类,我们必须更改它,这是架构的变化,可能可能破坏事物。但是,我并不想添加一个“天”。表等等。

无论如何,如果你想找到所有在星期一教学的老师,你可以这样做:

SELECT People.Name FROM People LEFT JOIN Teachers ON People.ID = Teachers.People_ID LEFT JOIN Classes ON People.ID = Classes.Teacher_ID LEFT JOIN Class_Times: ON Classes.ID = Class_Times.Class_ID WHERE Class_Times.Day = 'Monday';

或者,用一个很长的字符串格式化(就像它把它放在你的其他编程语言中一样):

People

基本上,这就是我们的工作:

  1. 选择我们想要的主要内容,即老师的名字。该名称存储在&{39; Teachers'表,所以我们先从中选择。
  2. 然后我们将其加入' Classes'表,告诉我们所选择的所有人都必须是教师。
  3. 之后,我们对' Class_Times';将其缩小到只有教师实际上自学的课程。
  4. 然后我们也抓住了{{1}}' (对于最后一步很重要),但仅适用于教师正在教授的那些课程。
  5. 最后,我们指定课程发生的日期必须是星期一'

答案 2 :(得分:1)

您需要为学生创建一个表,为时间表创建一个表,并在时间表中创建学生的外键。使用最佳实践,考虑到你有1000名学生,你将最终创建1000个表,而数据库是让生活更轻松。创建一个表,根据需要添加任意数量的条目。

其次,使用此结构更清楚地提出您的问题,以便我们能够帮助您

答案 3 :(得分:0)

表1:学生: id firstName lastName

表2:时间表: studentID 日期 classID

studentID(与Student.id相关)

classID(与Classes.id相关)

表3:类: id className teacherName

BOLD 是主键

这将收集所有拥有该老师的学生:

Select S1.firstName, S1.lastName, C.teacherName from Student as S1 join Schedule as S2 join Classes as C where S1.id = S2.studentID and S2.classID = C.id and C.teacherName = XXXX

这将收集所有特定班级的学生:

Select S1.firstName, S1.lastName from Student as S1 join Schedule as S2 where S1.id = S2.studentID and S2.classID = XXXX