代码之家  ›  专栏  ›  技术社区  ›  Nick Woodhams

MySQL的自连接是如何工作的?

  •  14
  • Nick Woodhams  · 技术社区  · 16 年前

    我最近问了一个关于自我加入的问题,我得到了一个很好的答案。

    查询的目的是在事件1之后1天内查找事件2的ID、开始日期和价格。

    代码工作正常。 但我不明白怎么做。

    有人能尽你所能详尽地解释一下查询的不同部分是什么,它们是做什么的吗?

    SELECT event2.id, event2.startdate, event2.price
    FROM mm_eventlist_dates event1
    JOIN mm_eventlist_dates event2 
    ON event2.startdate = date_add(event1.enddate, INTERVAL 1 DAY)
    WHERE event1.id=$id
    

    我真的很感谢你的帮助,不管是什么原因,我都很难在这件事上下功夫。

    4 回复  |  直到 11 年前
        1
  •  17
  •   ajsharma    13 年前

    我试图理解这一点的方法是在一个标记为event1和event2的条目上写出两个列表。然后在每个列表中列出几条记录(列表将完全相同),现在从下面描述的位置开始。

    我们正在从两个表中获取数据(好吧,同一个表使用了两次,但暂时忽略这一点)

    FROM mm_eventlist_dates event1
    JOIN mm_eventlist_dates event2 
    

    从下往上看可能会有帮助。

      WHERE event1.id=$id
    

    所以我们需要Event1中具有指定记录ID的记录。假设这正好是一条记录。现在我们计算出事件结束后的第二天。

     date_add(event1.enddate, INTERVAL 1 DAY)
    

    现在告诉我们事件2的记录,他们需要从那个日期开始,

    ON event2.startdate = date_add(event1.enddate, INTERVAL 1 DAY)
    

    我们现在识别了两个记录,我们需要哪些字段?

    SELECT event2.id, event2.startdate, event2.price
    

    哦,只是我们计算出开始日期的字段。

        2
  •  8
  •   Macros    16 年前

    当您在一个查询中创建一个联接时,您实际上就是这样做的-将两个表连接在一起。这可以是两个不同的表或两个相同的表,这并不重要。在指定联接时,如果表不同,则为表创建别名(在查询的其余部分中引用它的名称)很有用,如果表相同,则是必需的。您的查询采用表1(event1),其中包含以下列:

    event1.id, event1.startdate, event1.price
    

    以及连接表2(事件2):

    event2.id, event2.startdate, event2.price
    

    这将为您留下结果集:

    event1.id, event1.startdate, event1.price, event2.id, event2.startdate, event2.price
    

    联接的条件指定为:

    ON event2.startdate = date_add(event1.enddate, INTERVAL 1 DAY)
    

    意思是“对于event1中的每一行,加入event2中的行,该行的开始日期比event1中的开始日期晚1天”

    然后,因为您只对一个事件的数据感兴趣,所以WHERE子句限制了结果集。

    WHERE event1.id=$id
    

    最后,由于您不需要event1中有关原始事件的信息,因此select语句只需从resultset中选择event2列:

    SELECT event2.id, event2.startdate, event2.price
    
        3
  •  6
  •   Community CDub    11 年前

    自联接通过使用不同的选择条件两次引用同一个表来工作。将对表的每个引用都看作是通过过滤原始表而创建的不同“虚拟表”。通常,其中一个表使用WHERE子句进行“筛选”,第二个表在JOIN子句中进行“筛选”。这是最有效的方法,也可以在join子句中“过滤”两者。

    所以我们有两个基于同一基础表中数据的虚拟表,它们被连接在一起,就好像它们是两个完全独立的表一样。

    其关键在于,您将数据存储在一个表中,该表根据上下文具有稍微不同的含义。

    考虑一个人员表,每个人都有一个唯一的ID,以及一个父亲列

        id   name    fatherID
        1    Joseph  [null]
        2    Greg     1
    
        SELECT child.name as childName, father.name as fatherName
            FROM people as child
            INNER JOIN people as father on (child.fatherID = father.id)  
    

    将产生1行

        childName   fatherName
        Greg       Joseph
    
        4
  •  5
  •   Vinko Vrsalovic    16 年前

    联接根据特定条件组合两个表。标准是ON子句后面的内容。

    如果您将表与其自身联接起来,那么它实际上与创建表的副本、重命名表并使用该副本执行联接相同。

    例如

    Table foo         Table bar
    +---+---+---+     +---+---+---+
    | a | b | c |     | a | d | e |
    +---+---+---+     +---+---+---+
    | 1 | 2 | 3 |     | 1 | 0 | 0 |
    +---+---+---+     +---+---+---+
    | 1 | 3 | 4 |     | 2 | 9 | 3 |
    +---+---+---+     +---+---+---+
    | 1 | 3 | 5 |
    +---+---+---+
    | 2 | 4 | 6 |
    +---+---+---+
    

    如果我们这样做

    select * from foo join bar on (foo.a = bar.a and foo.c > 4)
    

    我们结束了

    foo join bar on (foo.a = bar.a and foo.c > 4)
    +---+---+---+---+---+
    | a | b | c | d | e |
    +---+---+---+---+---+
    | 1 | 3 | 5 | 0 | 0 |
    +---+---+---+---+---+
    | 2 | 4 | 6 | 9 | 3 |
    +---+---+---+---+---+
    
    

    现在,

    SELECT event2.id, event2.startdate, event2.price 
    FROM mm_eventlist_dates event1                     
    JOIN mm_eventlist_dates event2 
    ON event2.startdate = date_add(event1.enddate, INTERVAL 1 DAY)
    WHERE event1.id=$id
    

    该查询遵循相同的原则,但有两个表mm_eventlist_dates的实例,一个别名为event1,另一个别名为event2。我们可以将其想象为拥有两个表,并像在实际的两个表场景中那样执行连接。

    在这种情况下,联接条件是对于表event2,startdate与enddate加上表event1的一天匹配。

    WHERE子句限制执行的联接是什么,在这种情况下,它只对具有所提供ID的Event1表的行执行联接。