繁体   English   中英

将一个表与另一个表的最新行连接

[英]Join one table with the most recent rows of another

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

表1 (基本信息)

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

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

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

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)

我专门研究这种对时间敏感的设计,这就是我的工作。 您的第二张表是一个Versioned表,其中像源代码管理系统一样,当更改数据时,将保留旧数据,仅使用更改日期创建一个新副本。 进行很小的更改就可以添加完整的双向功能,但这不是您的问题,不是吗? 8)

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

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

然后,您可以简单地将第一个表与视图连接起来,以便与table1中的数据(仅在table2中的当前数据)具有一对一的关联。 这使您可以抽象化数据的时间敏感性。

如果由于某些原因您无法使用视图(例如,老式的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 );

如果“名称”和“日期”形成一个唯一索引(无论是显式定义还是因为它们构成了表的PK),您都会发现性能要比您最初想象的要好得多。 尝试一下,并与替代方案进行比较。

我通常在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)

试试这个,按日期分组

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
    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)

没有分组或聚合的查询:

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;
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连接到自身,以便找到给定名称的最新日期。

暂无
暂无

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

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