【问题标题】:Join one table with the most recent rows of another将一张表与另一张表的最新行连接起来
【发布时间】:2015-02-22 00:08:29
【问题描述】:

我有 2 个 MySQL 表,包含以下信息:

table1(基本信息)

name | url
a    | www.a.com
b    | www.b.com
c    | www.c.com

table2(时间序列数据)

name | status | date
a    | ok     | 22/12/14
b    | ok     | 22/12/14
c    | ok     | 22/12/14
a    | ok     | 21/12/14
b    | ok     | 21/12/14
c    | ok     | 21/12/14
etc

我需要进行连接,以便将 table1 中的所有条目与 table2 的最新条目连接起来。所以输出看起来像:

输出

name | url       | status | date
a    | www.a.com | ok     | 22/12/14
b    | www.b.com | ok     | 22/12/14
c    | www.c.com | ok     | 22/12/14

什么查询会给出上面的输出?

【问题讨论】:

标签: mysql sql join


【解决方案1】:

我通常在 SQLServer 中工作,因此如果适用,您必须更正语法,但基本上您将按可用的最大日期进行分组,并且只返回这些行。请参阅下面的代码并尝试一下!让我知道这是否有帮助。

SELECT t1.name, t1.url, t2.status, max(t2.date)
FROM table1 t1
INNER JOIN table2 t2 ON t1.name = t2.name
GROUP BY t1.name, t1.url, t2.status, max(t2.date)

【讨论】:

  • 看起来很有希望,但我收到“组函数的无效使用”错误
  • 抱歉,这可能是语法问题。看起来你的答案很听话,请试一试他们的一个。我很想知道哪一种对你有用。
【解决方案2】:

试试这个,按日期分组

SELECT  a.*,b.*
FROM    table1 a
        INNER JOIN
        (
            SELECT  table2.name name2, MAX(Date) max_date, status
            FROM    table2
            GROUP   BY name, status

        ) b ON  a.name = b.name2

【讨论】:

    【解决方案3】:
        Select t1.*, t2.status,t2.date 
        from table1 t1 inner join table t2 
        on t1.name = t2.name 
        where t2.date=(select max(date) from table2)
    

    【讨论】:

      【解决方案4】:

      这是一个棘手的问题。您可以做的是加入第二个表两次 - 一次查找“最新”行,第二次获取实际数据。

      SELECT t1.name, t1.url, t2.status, t2.date
      FROM table1 t1
      LEFT JOIN (SELECT name, max(date) as mx from table2 GROUP BY name) as X ON X.name = t1.name
      LEFT JOIN table2 t2 0N t2.name = X.name AND t2.date = X.mx
      

      我用名字加入。您通常会使用一些键(ID)

      【讨论】:

        【解决方案5】:
        SELECT t1.name, t1.url, t2.status, t2.date 
           FROM 
             table1 t1 
             JOIN table2 latest ON latest.name = t1.name 
             JOIN table2 t2 ON t2.name = latest.name AND t2.date = MAX(latest.date)
           GROUP BY t1.name, t1.url
        

        这样做是将 table2 连接到自身,以便找到给定名称的最新日期。

        【讨论】:

        • 聚合不能出现在 ON 子句中,除非它出现在 HAVING 子句或选择列表中包含的子查询中?
        【解决方案6】:

        没有分组或聚合的查询:

        SELECT t1.name, t1.url, t21.status, t21.date
        FROM table1 t1
        INNER JOIN table2 t21 ON t1.name = t21.name
        LEFT JOIN table2 t22 ON t21.name = t22.name AND t21.date < t22.date
        WHERE t22.name IS NULL;
        

        另一种新选择:

        SELECT t1.name, t1.url, t2.status, t2.date
        FROM table1 t1 INNER JOIN table2 t2 ON t1.name = t2.name
        WHERE t2.date = (SELECT max(date) FROM table2 t22 WHERE t22.name = t2.name);
        

        MySQL 不支持(还没有?)流行的窗口函数,这些函数已添加到当今大多数其他 RDBMS(Oracle、SQL Server、PostgreSQL)中。这就是使用 ROW_NUMBER 编写此类查询的自然方式:

        SELECT name, url, status, date from (
         SELECT t1.name, t1.url, t2.status, t2.date,
         ROW_NUMBER() OVER (PARTITION BY t1.name ORDER BY t2.date DESC) rn
         FROM table1 t1 INNER JOIN table2 t2 ON t1.name = t2.name
        ) tmp WHERE rn = 1;
        

        【讨论】:

          【解决方案7】:

          我专注于这种对时间敏感的设计,这就是我的工作。您的第二个表是Versioned 表,就像源代码控制系统一样,当数据发生更改时,旧数据仍然存在,只是制作了一个带有更改日期的新副本。一个小小的改变就可以添加完整的双时间功能,但这不是你的问题,是吗? 8)

          如果,就像我发现的那样,您注意到针对此表的绝大多数查询都是针对当前数据的,那么您可能需要考虑的一件事是创建一个视图以仅公开每个查询的当前版本行。

          create view tab2 as
          select *
          from   table2 t2
          where  date =(
              select  max( date )
              from    table2
              where   name = t2.name );
          

          然后您可以简单地将第一个表与视图连接起来,以便与表 1 中的数据与表 2 中的当前数据进行一对一的关联。这使您可以抽象出数据的时间敏感性。

          如果由于某些原因您不能使用视图(例如,老派 DBA 一想到要加入视图而癫痫发作),那么您必须将整个事情写成一个查询。幸运的是,这并不难,但抽象很方便。

          select t1.Name, t1.URL, t2.Status, t2.Date
          from   table1 t1
          join   table2 t2
            on   t2.Name = t1.Name
            and  t2.Date =(
                 select  max( Date )
                 from    table2
                 where   name = t2.name );
          

          某些 DBMS 不允许在连接中使用子查询。在这种情况下,只需将其移至 WHERE 子句:

          select t1.Name, t1.URL, t2.Status, t2.Date
          from   table1 t1
          join   table2 t2
            on   t2.Name = t1.Name
          where  t2.Date =(
                 select  max( Date )
                 from    table2
                 where   name = t2.name );
          

          如果 Name 和 Date 形成唯一索引(明确定义或因为它们形成表的 PK),您会发现性能比您最初想象的要好得多。尝试一下并与替代品进行比较。

          【讨论】:

          • 使用视图的另一个好处是您可以编写“之前”或“代替”触发器来将更新语句转换为正确的插入到新版本的表中,从而保持抽象.