Mysql 如何在聚合上联接表 问题摘要:

Mysql 如何在聚合上联接表 问题摘要:,mysql,Mysql,我需要基于聚合函数将单行连接到表输出,在本例中是最新的对应记录。关于此主题的各种其他问题似乎都是基于两个表的值都是必需的(内部联接,等等),但在我的情况下,聚合需要在一个左联接表上工作,该表多次将为空 MySQL 5.7; 以下是两个分层表: 桌子 我有一个关于几十个表的查询。从核心表中选择一行,并从几十个其他表中选择各种LEFT JOIN数据 图示的链接数据表包含日期数据,日期很重要,只返回最近的数据 示例数据: 我只想加入core_id=4和最大日期值的行。如何在JOIN场景中创建此功能;我

我需要基于聚合函数将单行连接到表输出,在本例中是最新的对应记录。关于此主题的各种其他问题似乎都是基于两个表的值都是必需的(
内部联接
,等等),但在我的情况下,聚合需要在一个
左联接
表上工作,该表多次将为

MySQL 5.7; 以下是两个分层表:

桌子 我有一个关于几十个表的查询。从核心表中选择一行,并从几十个其他表中选择各种
LEFT JOIN
数据

图示的链接数据表包含日期数据,日期很重要,只返回最近的数据

示例数据: 我只想加入core_id=4和最大日期值的行。如何在
JOIN
场景中创建此功能;我无法将
MAX
聚合放入
连接中。。。打开
状态

我当前的SQL: 我的SQL是这样的:

   SELECT ... many columns ..., 
   ld.data_value,
   ld.data_date,
   more.columns ... 
   FROM core
   LEFT JOIN table1 ON core.core_id = table1.core_id
   LEFT JOIN table2 ON core.core_id = table2.core_id
   LEFT JOIN table3 ON core.core_id = table3.core_id
   ... etc ...
   LEFT JOIN linked_data ld ON core.core_id = ld.core_id AND MAX(ld.data_date)
   WHERE ... core_id = value
一个表我只需要一个列中具有最高值的结果行(基于数据),没有理由
linked\u data
保存任何数据,因此左连接可能返回NULL

预期结果: 对于
core\u id=4
,我希望能够输出一个包含
linked\u data.data\u value=任何内容的SQL行结果。对于
core\u id=5
我希望能够从
链接的\u数据中输出其余数据,但不输出任何内容。
表格

我已经试过什么了?
  • 注意到它是正确的,但也注意到随着数据量的增加,它将变得非常缓慢

  • 将限定符放在
    WHERE
    子句中,但不能保证
    linked\u data
    将包含任何结果,因此,我当然可以在这里添加更多的条件(检查
    WHERE
    子句是否包含,但我希望避免这种情况

  • 有另一个可能的解决方案,但对此的评论也指出它非常慢(这可能是用户的错误,我还没有测试它)

  • 我还尝试在左连接中使用SELECT,如下所示:

     SELECT ... many columns ..., 
     ld.data_value,
     ld.data_date,
     more.columns ... 
     FROM core
     LEFT JOIN table1 ON core.core_id = table1.core_id
     LEFT JOIN table2 ON core.core_id = table2.core_id
     LEFT JOIN table3 ON core.core_id = table3.core_id
     ... etc ...
     LEFT JOIN (
         SELECT linked_data FROM linked_data ldi WHERE core.core_id = ldi.core_id AND MAX(ldi.data_date) 
     ) as ld ON core.core_id = ldi.core_id
     WHERE ... core_id = value
    
引用自

但这仍然告诉我这里不允许聚合调用

编辑:我发现了为什么不允许使用聚合;我犯了一个简单的语法错误;但我给出了一个完整的答案来澄清这个问题,因为我在搜索时找不到任何相关的答案,所以这可能对某些人有用


如果有人有更正确的方法来解决最初的问题,请分享!

在写出整个问题后,我发现在我的最新示例SQL上的一个简单语法修复解决了正确的方法(我过去用正确的方法做过,但还没有学会)

我注意到我的问题在互联网上缺乏(或者说我无法轻松找到)明确的答案,所以这里是我的方法

对于从联接表中获取0或1结果,执行此类聚合联接的正确方法如下所示:

  • 左连接
    ,然后将子查询用括号括起来,并按常规将其设置为…
  • 将聚合函数放入子查询中,忽略联接条件;联接条件将位于外部查询的“…”部分
  • 在子查询中使用
    orderby
    ,然后在该点设置聚合
  • 所以,

    子查询中不需要
    WHERE
    ,但如果这样做,则显然它应该是静态的,不需要引用外部表,就像在
    on
    子句中所做的那样。为了熟悉起见,我输入了
    WHERE optional=1

    LEFT JOIN
    的本质是它将返回0或1个结果,因此我发现不需要太多其他结果

    如果有人有更好的方法解决我的原始问题,请让我知道


    p.s>我根本没有对这个答案进行效率测试。

    在提供给您的最短示例答案中……您可以使用一个预查询来生成加入的别名。此预查询可以为每个核心分组/max

    也就是说,由于链接的数据表是自动递增的,我会假设(是的,我知道假设,但您可以确认)在添加每个记录时,日期将始终是添加的日期。因此,ID为100的日期可能为2020年1月14日,您将永远不会有ID更高的较早日期记录,例如ID 101=2019年11月3日。添加每个ID时,无论核心ID如何,日期都将高于上一个记录

    然后,您可以根据需要继续与其他表进行附加的“左联接”

    评论澄清的修订

    Martin,根据您提供的关于来自多个来源的数据和日期可能代表较旧数据的说明,只需将查询前的内部sql修改为以下内容即可。该查询被大量注释,以说明在这种情况下,over/partition查询是如何工作的

    现在,与您的所有其他内容集成。我将仅以左连接的形式连接到您的主核心表

    select
          cd.core_id,
          cd.some_name,
          cd.some_data,
          cd.some_values,
          ld2.link_id,
          ld2.data_date,
          ld2.some_linked_data_values
       from
          core_data cd
             left join
             ( select pq1.* 
                 from
                   -- first, all columns I want to have returned from 
                   -- the linked_data table
                   ( select core_id, 
                            data_date, 
                            link_id, 
                            -- dense_rank() returns sequential counter value
                            -- starting at 1 based on every change of the 
                            -- PARTITION BY Core_ID in next part below
                            dense_rank() 
                        over ( partition by 
                                  -- primary sorting by the core_id
                                  core_id 
                               order by 
                                  -- then within each core_id, descending by date
                                  data_date desc, 
                                  -- and then by the link_id descending, just in case
                                  -- there are multiple records for the same core_id
                                  -- AND the same date... So you get the most
                                  -- recently added linked_data record for given core
                                  link_id desc ) as sqlrow
                        from linked_data ) pq1
                where
                   -- now, from inner partition/over query, only get the record
                   -- where the sqlrow = 1, as result of dense_rank()
                   -- that resets to 1 every time core_id changes
                   pq1.sqlrow=1 ) PQ
                 on cd.core_id = PQ.core_id
                    LEFT JOIN linked_data ld2
                       on PQ.Link_id = ld2.link_id
    
    带有OVER/PARTITION BY的内部查询基本上是对数据进行第一次传递,并首先按分区(核心id)对数据进行排序,然后按数据_日期降序进行子排序(因此,无论从任何外部源导入的数据是较早还是较晚添加的,都是最新的日期),然后根据为任何给定日期添加的最新记录按链接id降序进行子排序


    最后一个外部WHERE子句基本上是说,只返回每个核心id的第一行。因此,现在,您有了适当的关键元素,可以将左连接重新连接到原始核心id,但也有适当的链接id,以便在最终查询结果中获得适当的记录。

    谢谢。
    数据日期
     SELECT ... many columns ..., 
     ld.data_value,
     ld.data_date,
     more.columns ... 
     FROM core
     LEFT JOIN table1 ON core.core_id = table1.core_id
     LEFT JOIN table2 ON core.core_id = table2.core_id
     LEFT JOIN table3 ON core.core_id = table3.core_id
     ... etc ...
     LEFT JOIN (
         SELECT linked_data FROM linked_data ldi WHERE core.core_id = ldi.core_id AND MAX(ldi.data_date) 
     ) as ld ON core.core_id = ldi.core_id
     WHERE ... core_id = value
    
       SELECT ... many columns ..., 
       ld.data_value,
       ld.data_date,
       more.columns ... 
       FROM core
       LEFT JOIN table1 ON core.core_id = table1.core_id
       LEFT JOIN table2 ON core.core_id = table2.core_id
       LEFT JOIN table3 ON core.core_id = table3.core_id
       ... etc ...
       LEFT JOIN (
           SELECT linked_data FROM linked_data ldi WHERE optional = 1 ORDER BY MAX(ldi.data_date) 
       ) as ld ON core.core_id = ldi.core_id
       WHERE ... core_id = value
    
    select
          cd.core_id,
          cd.some_name,
          cd.some_data,
          cd.some_values,
          ld2.link_id,
          ld2.data_date,
          ld2.some_linked_data_values
       from
          core_data cd
             left join
             ( select pq1.* 
                 from
                   -- first, all columns I want to have returned from 
                   -- the linked_data table
                   ( select core_id, 
                            data_date, 
                            link_id, 
                            -- dense_rank() returns sequential counter value
                            -- starting at 1 based on every change of the 
                            -- PARTITION BY Core_ID in next part below
                            dense_rank() 
                        over ( partition by 
                                  -- primary sorting by the core_id
                                  core_id 
                               order by 
                                  -- then within each core_id, descending by date
                                  data_date desc, 
                                  -- and then by the link_id descending, just in case
                                  -- there are multiple records for the same core_id
                                  -- AND the same date... So you get the most
                                  -- recently added linked_data record for given core
                                  link_id desc ) as sqlrow
                        from linked_data ) pq1
                where
                   -- now, from inner partition/over query, only get the record
                   -- where the sqlrow = 1, as result of dense_rank()
                   -- that resets to 1 every time core_id changes
                   pq1.sqlrow=1 ) PQ
                 on cd.core_id = PQ.core_id
                    LEFT JOIN linked_data ld2
                       on PQ.Link_id = ld2.link_id