【问题标题】:SQL function to create a one-to-one match between two tables?用于在两个表之间创建一对一匹配的 SQL 函数?
【发布时间】:2019-10-23 07:50:38
【问题描述】:

我正在尝试加入 2 个表。 Table_A 有 ~145k 行,而 Table_B 有 ~205k 行。

它们有两列共同(即 ISIN 和日期)。但是,当我执行此查询时:

SELECT A.*,
       B.column_name

FROM   Table_A
       JOIN
       Table_B ON A.date = B.date

WHERE  A.isin = B.isin

我得到一个超过 147k 行的表。这怎么可能?它不应该返回一个最多包含 ~145k 行的表吗?

【问题讨论】:

  • 不,如果在同一日期存在重复记录并且在您所在的位置,每次加入您将获得 2 行或更多行
  • 不知道你的表结构,但使用日期加入不是很好的做法,如果可能的话,在你的表中使用整数值加入。关于为什么行数比你预期的多,你的表中可能有重复的记录也需要过滤掉。
  • 这是一个常见问题解答。在考虑发布之前,请始终使用谷歌搜索您的错误消息或您的问题/问题/目标的许多清晰、简洁和精确的措辞,有或没有您的特定字符串/名称和站点:stackoverflow.com 和标签,并阅读许多答案。如果您发布问题,请使用一个短语作为标题。请参阅How to Ask 和投票箭头鼠标悬停文本。 PS请在代码问题中给出minimal reproducible example--剪切&粘贴&可运行代码;具有期望和实际输出(包括逐字错误消息)的示例输入(作为初始化代码);标签和版本;明确的规范和解释。

标签: sql sql-server join


【解决方案1】:

您所看到的表明,对于Table_A 中的某些记录,Table_B 中有几条记录满足连接条件((date, isin) 元组上的相等性)。

要展示这些记录,您可以:

select B.date, B.isin
from Table_A
join Table_B on A.date = B.date and A.isin = B.isin
group by B.date, B.isin
having count(*) > 1

由您决定如何处理这些重复项。例如:

  • 如果重复项在column_name列中具有不同的值,那么您可以决定提取最大值或最小值

  • 或使用另一列过滤重复项中的顶部或底部记录

  • 如果重复项是真正的重复项,那么您可以在子查询中使用select distinct 在加入之前对它们进行去重

  • ...其他解决方案也是可能的...

【讨论】:

    【解决方案2】:

    如果您希望每个表 A 有一行,则使用 outer apply:

    SELECT A.*,
           B.column_name
    FROM Table_A a OUTER APPLY
         (SELECT TOP (1) b.*
          FROM Table_B b
          WHERE A.date = B.date AND A.isin = B.isin
          ORDER BY ?  -- you can specify *which* row you want when there are duplicates
         ) b;
    

    OUTER APPLY 实现横向连接。 TOP (1) 确保最多返回一行。 OUTER(相对于CROSS)确保不会过滤掉任何内容。在这种情况下,您还可以将其表述为相关子查询。

    话虽如此,您的数据似乎并不是您真正期望的。您应该弄清楚重复项的来源。开始的地方是:

    select b.date, b.isin, count(*)
    from tableb b
    group by b.date, b.isin
    having count(*) >= 2;
    

    这将向您显示重复项,以便您了解如何处理它们。

    【讨论】:

      【解决方案3】:

      已经讨论了重复的可能性。

      当在连接中使用数百万条记录时,通常是由于 Cardianility Estimate 不佳, 记录返回不准确。

      为此只需更改加入顺序,

      SELECT A.*,
             B.column_name
      FROM   Table_A
             JOIN
             Table_B ON A.isin = B.isin 
          and
      A.date = B.date
      

      同时在两个表上创建非聚集索引。

      Create NonClustered index isin_date_table_A on Table_A(isin,date)include(*Table_A)
      

      *Table_A= 结果集中需要的逗号分隔列表 Table_A 列

      Create NonClustered index isin_date_table_B on Table_B(isin,date)include(column_nameA)
      

      Update STATISTICS Table_A

      Update STATISTICS Table_B

      【讨论】:

        【解决方案4】:

        在 JOIN 条件中保持两个表的 DATE 列格式相同,您应该会得到预期的结果。

        Select A.*, B.column_name
        from Table_A
        join Table_B on to_date(a.date,'DD-MON-YY')  = to_date(b.date,'DD-MON-YY') 
         where A.isin = B.isin
        

        【讨论】:

          猜你喜欢
          • 2017-12-16
          • 1970-01-01
          • 2020-10-08
          • 1970-01-01
          • 2023-03-25
          • 1970-01-01
          • 2018-03-06
          • 2020-01-31
          • 1970-01-01
          相关资源
          最近更新 更多