简体   繁体   English

MySQL:了解映射表

[英]MySQL: Understanding mapping tables

When building a category navigation system for a business directory with a many to many relationship, I understand that it is good practise to create a mapping table. 在为具有多对多关系的业务目录构建类别导航系统时,我理解创建映射表是一种好习惯。

Category Table ( CategoryId, CategoryName ) 类别表(CategoryId,CategoryName)
Business Table ( BusinessId, BusinessName ) 业务表(BusinessId,BusinessName)
Category Mapping Table ( BusinessId, CategoryId ) 类别映射表(BusinessId,CategoryId)

When I join the Category table and Business table to create the mapping table would this then give me a table which contains every possible business and category relationship? 当我加入Category表和Business表来创建映射表时,这会给我一个包含每个可能的业务和类别关系的表吗?

I have 800 categories and 1000 business listings. 我有800个类别和1000个商家信息。 Would that then give me a table containing 800,000 possible relationships. 那会不会给我一张包含800,000种可能关系的表格。 If so how would I focus on only the relationships that exist? 如果是这样,我将如何只关注存在的关系? Would I have to go through all listings (800,000) marking them as true or false? 我是否必须通过所有列表(800,000)将其标记为真或假?

I have been getting really confused about this so any help would be much appreciated. 我对此非常困惑,所以任何帮助都会非常感激。

When using many-to-many relationships, the only realistic way to handle this is with a mapping table. 使用多对多关系时,处理此问题的唯一现实方法是使用映射表。

Lets say we have a school with teachers and students, a student can have multiple teachers and visa versa. 假设我们有一所学校,老师和学生,一个学生可以有多个老师,反之亦然。

So we make 3 tables 所以我们制作3张桌子

student
  id unsigned integer auto_increment primary key
  name varchar

teacher
  id unsigned integer auto_increment primary key
  name varchar

link_st
  student_id integer not null
  teacher_id integer not null
  primary key (student_id, teacher_id)

The student table will have 1000 records 学生表将有1000条记录
The teacher table will have 20 records 教师表将有20条记录
The link_st table will have as many records as there are links (NOT 20x1000, but only for the actual links). link_st表将包含与链接一样多的记录(非20x1000,但仅适用于实际链接)。

Selection 选择
You select eg students per teacher using: 您可以选择每位教师使用的学生:

SELECT s.name, t.name 
FROM student
INNER JOIN link_st l ON (l.student_id = s.id)   <--- first link student to the link-table
INNER JOIN teacher t ON (l.teacher_id = t.id)   <--- then link teacher to the link table.
ORDER BY t.id, s.id

Normally you should always use an inner join here. 通常,您应该始终在此处使用inner join

Making a link 建立链接
When you assign a teacher to a student (or visa versa, that's the same) . 当您将教师分配给学生时(反之亦然,这是相同的) You only need to do: 你只需要这样做:

INSERT INTO link_st (student_id, teacher_id) 
   SELECT s.id, t.id 
   FROM student s 
   INNER JOIN teacher t ON (t.name = 'Jones')
   WHERE s.name = 'kiddo'

This is a bit of a misuse of an inner join, but it works as long as the names are unique. 这有点滥用内连接,但只要名称是唯一的,它就会起作用。
If you know the id's, you can just insert those directly of course. 如果你知道id,你可以直接插入它们。
If the names are not unique this will be a fail and should not be used. 如果名称不唯一,则将失败 ,不应使用。

How to avoid duplicate links 如何避免重复链接
It's very important to avoid duplicate links, all sorts of bad things will happen if you have those. 避免重复链接非常重要,如果你有这些链接会发生各种不好的事情。
If you want to prevent inserting duplicate links to your link table, you can declare a unique index on the link (recommended) 如果要防止在链接表中插入重复链接,可以在链接上声明unique索引(推荐)

ALTER TABLE link_st
  ADD UNIQUE INDEX s_t (student_id, teacher_id); 

Or you can do the check in the insert statement (not really recommended, but it works). 或者您可以在insert语句中进行检查(不是真的推荐,但它可以工作)。

INSERT INTO link_st (student_id, teacher_id) 
  SELECT s.id, t.id
  FROM student s
  INNER JOIN teacher t ON (t.id = 548)
  LEFT JOIN link_st l ON (l.student_id = s.id AND l.teacher_id = t.id)
  WHERE (s.id = 785) AND (l.id IS NULL)

This will only select 548, 785 if that data is not already in the link_st table, and will return nothing if that data is in link_st already. 如果该数据不在link_st表中,则仅选择link_st如果该数据已在link_st中, link_st返回任何内容。 So it will refuse to insert duplicate values. 因此它将拒绝插入重复值。

If you have a table schools, it depends if a student can be enrolled in multiple schools (unlikely, but lets assume) and teachers can be enrolled in multiple schools. 如果你有一个表学校,这取决于学生是否可以在多所学校注册(不太可能,但我们假设),教师可以在多所学校注册。 Very possible. 非常可能。

table school
  id unsigned integer auto_increment primary key
  name varchar

table school_members
  id id unsigned integer auto_increment primary key
  school_id integer not null
  member_id integer not null
  is_student boolean not null

You can list all students in a school like so: 您可以列出学校中的所有学生:

SELECT s.name
FROM school i
INNER JOIN school_members m ON (i.id = m.school_id)
INNER JOIN student s ON (s.id = m.member_id AND m.is_student = true)

When I join the Category table and Business table to create the mapping table would this then give me a table which contains every possible business and category relationship? 当我加入Category表和Business表来创建映射表时,这会给我一个包含每个可能的业务和类别关系的表吗?

Yes. 是。

Would I have to go through all listings (800,000) marking them as true or false? 我是否必须通过所有列表(800,000)将其标记为真或假?

No, you need to use the ON -clause to set join-conditions. 不,您需要使用ON -clause来设置join-conditions。

SELECT <columns> FROM categories as c 
INNER JOIN mapping AS m
    ON m.CategoryId = c.CategoryId
INNER JOIN businesses as b
    ON m.BusinessId = b.BusinessId

You should use mapping tables when you are trying to model a many-to-many or one-to-many relationship. 在尝试建模多对多关系或一对多关系时,应使用映射表。

For example, in an address book application, a particular contact could belong to zero, one or many categories. 例如,在地址簿应用程序中,特定联系人可以属于零个,一个或多个类别。 If you set your business logic that a contact can only belong to one category, you would define your contact like: 如果您将业务逻辑设置为联系人只能属于一个类别,则可以将联系人定义为:

Contact
--------------
contactid (PK)
name
categoryid (FK)

Category
--------------
categoryid (PK)
categoryname

But if you wanted to allow a contact to have more than one email address, use a mapping table: 但是,如果您希望允许联系人拥有多个电子邮件地址,请使用映射表:

Contact
--------------
contactid (PK)
name

Category
--------------
categoryid (PK)
categoryname

Contact_Category
--------------
contactid (FK)
categoryid (FK)

Then you can use SQL to retrieve a list of categories that a contact is assigned to: 然后,您可以使用SQL来检索联系人分配到的类别列表:

select a.categoryname from Category a, Contact b, Contact_Category c where a.categoryid=c.categoryid and b.contactid=c.contactid and b.contactid=12345; 从类别a,联系人b,Contact_Category c中选择a.categoryname,其中a.categoryid = c.categoryid,b.contactid = c.contactid和b.contactid = 12345;

select a.categoryname 
from Category a
inner join Contact_Category c on a.categoryid=c.categoryid
inner join Contact b on b.contactid=c.contactid
where b.contactid=12345;

you only put the real relationships in the mapping table. 你只把真正的关系放在映射表中。 so on average fi a business is in 2 categories, then in your example, there would only be 2000 records in the mapping table, not 800,000 所以平均而言,一个企业属于两个类别,那么在你的例子中,映射表中只有2000条记录,而不是800,000条

"When I join the Category table and Business table to create the mapping table" you don't join those two tables to create the mapping table. “当我加入Category表和Business表来创建映射表时”,你不要加入这两个表来创建映射表。 You create an actual physical table. 您创建一个实际的物理表。

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

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