繁体   English   中英

SQL多表和多列选择

[英]SQL Multi Table and Multi Column Select

我正在创建一个mysql数据库,该数据库为学校中的每个学生提供一个表,然后在每个表中都有每个学生的时间表。 我需要能够运行一个脚本,该脚本将搜索数据库中的每个表和每个列中的2个值。 例如,它需要在所有表和列中搜索教师“ x”,其中day_week = MondayA。 在该表中,共有11列,一列是day_week,然后是五节,这是每节课的时间(因此,第一节课,第二节课等),然后是另外五列。

任何帮助将非常感激。

谢谢。

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

就是说,要回答您的问题:您需要在架构(information_schema表)中查询表和列的列表,然后循环查询表。

info_schema上mysql文档开始

修正您的架构

首先,您的架构听起来很糟糕。 每次添加新学生时,都必须更改它(添加新表),如果这是一所真正的学校,那绝对是一场灾难! 更改架构比仅在表中插入一行要昂贵得多,并且如果您的Web应用程序可以直接更改数据库,那么任何可能暴露的安全漏洞都可能导致人们在不认识表的情况下弄乱您的表。

最重要的是,它使查询学生的人数成为绝对的痛苦 理想情况下,数据的布局应使您能够回答可能遇到的所有问题。 不仅您现在有疑问,而且还有进一步的疑问。

如果这还不够糟糕的话,它会使查询成为噩梦。 您必须以某种方式跟踪表的数量及其名称,以便每次查询信息时它都在运行完全不同的查询。 某些查询(例如“列出去年加入的学生列表”)随着学生列表(表数)的增长而增加了规模,复杂度和运行时间。 这可能是您已经遇到的问题,尽管很难从您的问题中分辨出来。

正常化

简而言之,规范化是“精心设计架构”。 这是一个模糊的话题,但是它分为不同的层次。 每个级别都取决于最后一个级别。

老实说,我不理解不同级别的措辞,而且我本人还是数据库的新手,但是根据我的教导,这是归一化的要旨:

每个值都意味着一件小而简单的事情

基本上,不要发疯,把很多东西放在一栏中。 有一列类似' Categories '的值是不好的设计,其值必须是一个长字符串,其内容类似于"Programming, Databases, Web Development, MySQL, Cows"

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

我不确定这是否是规范化的一部分,但是我学会了做的是为多个表中引用的所有内容创建一个数字“ ID”。 例如,我将使用'ID', 'Name', 'Address', 'Birthday'代替具有'Name', 'Address', 'Birthday'列的数据库表。 ID将是每一行的唯一数字,主键,并且如果在任何时候我想引用其中的任何人,我只会使用该数字。

数字可以更快地进行比较/匹配,查找和查找,并且整体上对数据库的处理要好得多,并且您可以创建查询,而这些查询的运行时间与基于字符串的数据库相比只占很小的一部分。

为了完成该示例,您可以有三个表; 例如“ Articles ”,“ Categories ”和“ Article_Categories ”。

Articles ”将保留所有实际的文章及其属性。 诸如'ID', 'Title', 'Content'

Categories ”将保存所有可用的单个类别,并带有“ ID ”和“ Category ”字段。

Article_Categories ”将按类别组合文章; “商品Article_ID ”和“ Category_ID Article_ID ”的唯一组合。

这可能是什么样的:

  • 文章
    • 1,“ Web Cow Geniuses”,“ Cow已被证明知道如何使用MySQL为网站创建出色的数据库”。
    • 2,“为什么要使用MySQL”,“它是免费的,du!”
  • 分类目录
    • 1,奶牛;
    • 2,数据库;
    • 3,MySQL;
    • 4,编程;
    • 5,网站开发;
  • 文章_类别
    • 1,1;
    • 1、2;
    • 1、3;
    • 1、4;
    • 1、5;
    • 2 2
    • 2 3

注意“ Article_Categories ”中的每个组合都是唯一的; 例如,您永远不会看到两次“ 1、3”。 但是“ 1”多次出现在第一列中,而“ 3”多次出现在第二列中。

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

不要混合数据和元数据

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

数据内部的元数据

这是将元数据放入数据中的示例:

  • 一个“ People ”表,其中具有“ isStudent ”和“ isTeacher ”作为列。

将数据放入“ People ”时,您可能在一行中既是教师又是学生,因此您要输入诸如'ID', 'Name', 'yes', 'yes' 这听起来不错,而且很可能有一位老师在同一所学校上课,所以这是可能的。

但是,由于您必须在两列中都具有某种值,即使它们只是一个或另一个,也要占用更多空间。

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

  • 一个“ People ”表,其中包含每个人的ID,姓名和其他数据。
  • 一个“ Students ”表,仅使用“ People.ID ”的值作为数据。
  • 一个“ Teachers ”表,仅使用“ People.ID ”的值作为数据。

这样,在“ Students ”中引用了每个Students ,而在“ Teachers ”中引用了每个Teachers 如前所述,我们使用“ ID ”字段,因为它可以更快地跨表匹配。 现在,所引用的老师数量与所需的数量一样多,对学生而言也是如此。 由于将它们作为单独的表的大小开销,最初占用了更多的空间,但是随着数据库的增长,这已经远远超过了弥补。

这也使您可以直接推荐老师。 假设您有一张“ Classes ”表,并且只希望有能力成为老师的老师。 您的“ Classes ”表在“ Teachers ”列中,可以有一个指向“ Teachers.ID ”的外键。 这样,如果学生入侵数据库并试图以某种方式将自己摆在课堂教学中,那么他们就不可能这样做。

元数据中的数据

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

从本质上讲,数据就是我们要存储的数据。 学生姓名,老师姓名,两者的时间表等。但是,有时我们将数据-如学生姓名-放在元数据中-如表名。

每当您看到自己定期添加或更改数据库架构时,这都是巨大的迹象,表明您正在将数据放入元数据中。 在您的情况下,每个拥有自己表的学生实际上都是将其姓名放在元数据中。

现在,有些时候您想这样做,但是表的数量不会经常改变。 它可以使事情变得更简单。例如,如果您有一个销售内衣的网站,则可能同时具有“ Mens_Products ”和“ Womens_Products ”表。 显然,“整洁”的解决办法是有一个“ Product_Categories ”表中,如果你想变性的产品或其他销售产品添加两种性别,但在这种情况下,它不管那么多 添加“ Trans_Products ”表并不难,这不像您经常添加新表那样。

不重复数据

起初,这听起来像我在与我刚才所说的一切相矛盾。 “如果不应该复制数据,我应该如何在所有地方复制这些ID ?!” 但是,a,这并不是我的意思。 实际上,这是您可能要引用的每个项目都具有单独ID的另一个原因!

本质上,您不需要更新比所需更多的数据。 例如,如果在上例中的“ Students ”和“ Teachers ”表中都有“ Birthday ”列,并且您既有学生又有教师,则突然将他们的生日记录在两个不同的位置! 现在,如果生日不对,您想更改生日怎么办? 您必须将其更改两次

因此,您将其放在“ People ”表中。 这样,对于每个人来说,它只存在一次。

这似乎是一个显而易见的例子,但是您会意外地发现它经常发生。 请小心,并注意任何需要您在两个不同位置更新相同值的事情。

查询

那么,尽管如此,您应该如何查询? 您应该使用哪种SELECT语句?

假设您具有以下架构(主键以粗体显示):

  • 人:
    • ID
    • 名称(唯一)
    • 生日
  • 教师:
    • People_ID (外国人:People.ID)
  • 学生们:
    • People_ID (外国人:People.ID)
  • 类:
    • ID
    • 名称(唯一)
    • Teacher_ID(外国人:Teachers.ID)
  • 上课时间:
    • Class_ID (国外:Classes.ID)
    • 日期 (枚举:“星期一”,“星期二”,“星期三”,“星期四”,“星期五”,“星期六”)
    • 开始时间
  • 学生班:
    • Student_ID (外国人:Students.ID)
    • Class_ID (国外:Classes.ID)

首先请注意,“ Student_Classes ”具有两个主键...这使两个键(而不是单个键) 组合在一起 如前所述,这使其成为一个多对多表。 我也是针对“ Class_ID ”和“ Day ”这样做的,这样您就不会在同一天两次上课。

同样,在一周中的某天使用Enum可能很糟糕...如果要添加Sunday类,则必须进行更改,这是架构中的更改,可能破坏事情。 但是,我不想添加“ Days”表和所有其他内容。

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

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

本质上,这是我们的工作:

  1. 选择我们想要的主要内容,老师的名字。 名称存储在“ People ”表中,因此我们首先从中选择。
  2. 然后,我们将其加入“ Teachers ”表,告诉我们我们选择的所有人员都必须是一名教师。
  3. 之后,我们对“ Classes ”进行相同的操作; 将其范围缩小到仅教师实际自学的班级。
  4. 然后,我们还抓取“ Class_Times ”(对于最后一步很重要),但仅适用于教师正在教授的那些班级。
  5. 最后,我们指定上课的日期必须为“星期一”。

您需要为学生创建一个表,为时间表创建一个表,并在时间表中具有学生的外键。 使用最佳实践,假设您有1000名学生,那么当数据库存在时,您最终将创建1000个表,这会使生活变得更轻松。 创建一个表,添加任意数量的条目。

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

表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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM