Mysql LEFT JOIN GROUP BY LAST 每个表的记录

Posted

技术标签:

【中文标题】Mysql LEFT JOIN GROUP BY LAST 每个表的记录【英文标题】:Mysql LEFT JOIN GROUP BY LAST Records from each Table 【发布时间】:2020-09-08 18:37:38 【问题描述】:

我想链接几个表,并在链接表中拥有每个条目的最后记录。

例如

Tabelle Domain

-- ID -- | -- DOMAIN -- | -- DATE --
    1         seite.de      08-09-2020
 
Tabelle Domain Verify

-- ID -- | -- DOMAIN_ID -- | -- IS SSL -- | -- DATE --
    1               1             0            06-09-2020
    2              1              1            07-09-2020
    3              1              1            08-09-2020
 
Tabelle Domain SSL

-- ID -- | -- DOMAIN_ID -- | -- SSL NAME -- | -- DATE --
    1                   1           NOT             06-09-2020
    2                  1            ENCRYPT          07-09-2020
    3                  1            ENCRYPT           08-09-2020

Tabelle Revoked:

-- ID -- | -- DOMAIN_ID -- | -- REVOKED -- | -- DATE --
    1                  1          1           06-09-2020
    2                  1          0           07-09-2020
    3                  1          0           08-09-2020

现在他在域 SSL 表中向我显示 SSL 名称不是。但想展示从 08.09 开始的 ENCRYPT STANDS 的最新帖子

SELECT

domain.id,

domain_verify.domain_id,
domain_verify.ssl_check

domain_ssl.domain_id,
domain_ssl.ssl_name,

domain_ssl_revoked.domain_id,
domain_ssl_revoked.revoked

FROM domain

LEFT JOIN domain_verify
ON domain_verify.domain_id = domain.id

LEFT JOIN domain_ssl
ON domain_ssl.domain_id = domain_verify.id

LEFT JOIN domain_ssl_revoked
ON domain_ssl_revoked.domain_id = domain_verify.id

GROUP BY domain_verify.id ORDER BY domain_verify.date DESC 

【问题讨论】:

哪个版本的mysql,能不能显示出预期的数据。 你应该学习如何使用GROUP BY。您的代码不应该执行。它应该会出错。 【参考方案1】:

考虑通过相应的聚合查询加入。下面使用表别名来提高可读性(即减少所有 domain 引用)。

SELECT d.id
     , v.domain_id AS v_domain_id, v.ssl_check
     , s.domain_id AS s_domain_id, s.ssl_name
     , r.domain_id AS r_domain_id, r.revoked

FROM domain d

LEFT JOIN domain_verify v ON v.domain_id = d.id
INNER JOIN 
    (SELECT domain_id, MAX(date) as max_date
     FROM domain_verify v
     GROUP BY domain_id) agg_v
  ON  agg_v.domain_id = v.domain_id
  AND agg_v.max_date = v.date

LEFT JOIN domain_ssl s ON s.domain_id = v.id
INNER JOIN 
    (SELECT domain_id, MAX(date) as max_date
     FROM domain_ssl
     GROUP BY domain_id) agg_s
  ON  agg_s.domain_id = s.domain_id
  AND agg_s.max_date = s.date

LEFT JOIN domain_ssl_revoked r ON r.domain_id = v.id
INNER JOIN 
    (SELECT domain_id, MAX(date) as max_date
     FROM domain_ssl_revoked
     GROUP BY domain_id) agg_r
  ON  agg_r.domain_id = r.domain_id
  AND agg_r.max_date = r.date

ORDER BY v.date DESC 

如果你有一天支持window functions(在 MySQL 8.0+ 中合并),请考虑标记行并检查最大日期。

SELECT `id`, `date`, v_domain_id, ssl_check, ssl_namme, revoked
FROM
   (SELECT d.id
         , v.date, v.domain_id AS v_domain_id, v.ssl_check
         , s.domain_id AS s_domain_id, s.ssl_name
         , r.domain_id AS r_domain_id, r.revoked
         , if(v.date = MAX(v.date) OVER(PARTITION BY v.domain_id), 1, 0) AS latest_v_dt
         , if(s.date = MAX(s.date) OVER(PARTITION BY s.domain_id), 1, 0) AS latest_s_dt
         , if(r.date = MAX(r.date) OVER(PARTITION BY r.domain_id), 1, 0) AS latest_r_dt
    FROM domain d  
    LEFT JOIN domain_verify v 
          ON v.domain_id = d.id AND latest_v_dt = 1   
    LEFT JOIN domain_ssl s
          ON s.domain_id = v.id AND latest_s_dt = 1   
    LEFT JOIN domain_ssl_revoked r
          ON r.domain_id = v.id AND latest_r_dt = 1
   ) sub    
ORDER BY `date` DESC 

【讨论】:

以上是关于Mysql LEFT JOIN GROUP BY LAST 每个表的记录的主要内容,如果未能解决你的问题,请参考以下文章

带有 LEFT JOIN 和 GROUP BY 的 COUNT(*) 在 MySQL 中包含 NULL

来自 GROUP_BY 的两个 LEFT JOIN 的 GROUP_CONCAT 的奇怪重复行为

SQL 笔记1,left join,group by,having

SQL GROUP BY 与 LEFT JOIN MS SQL Server

带有 WHERE 子句的 GROUP BY 以及 sql 中的 OR 的 LEFT JOIN

SQL sum()后许多字段要group by不使用group by, 改用left join select 需要的字段。哪个方法好?速度快?