【问题标题】:tsql: alternative to select subquery in jointsql:在连接中选择子查询的替代方法
【发布时间】:2014-02-03 11:31:18
【问题描述】:

这是我简化的表格布局:

table1:pID(pkey),数据 table2:rowID(pkey)、pID(fkey)、数据、日期

我想从 table1 中选择一些行,将每个 pID 的 table2 中的一行连接到该 pID 的最近日期。 我目前使用以下查询执行此操作:

SELECT * FROM table1 as a
LEFT JOIN table2 AS b ON b.rowID = (SELECT TOP(1) rowID FROM table2 WHERE pID = a.pID ORDER BY date DESC)

这种工作方式很慢,可能是因为它必须对表 1 的每一行进行子查询。有没有办法提高性能或另一种方式?

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    您可以在这些行上进行尝试,使用子查询根据日期字段(按 pID 分组)获取最新的,然后将其与第一个表连接,这样子查询就不必执行对于 Table1 的 每一 行,将产生更好的性能:

    Select *
    FROM Table1 a
    INNER JOIN 
       (
        SELECT pID, Max(Date) FROM Table2
        GROUP BY pID
       ) b
    ON a.pID = b.pID
    

    我已经使用 group by 为一列提供了示例 SQL,如果您需要其他列,请将它们添加到 GROUP BY 子句中。希望这会有所帮助。

    【讨论】:

    • 这确实快了很多。但是在 table2 中,我还需要返回一列,因此您的代码将变为:Select a.pID, a.data, b.data FROM Table1 a INNER JOIN ( SELECT pID, Max(Date), data FROM Table2 GROUP BY pID, data ) b ON a.pID = b.pID 这样我们将获得一个 pID 的多个值,我只需要最近的一个。
    • 很高兴这有帮助:-)。是的,您需要添加您的案例所需的其他列。
    【解决方案2】:

    使用下面的代码,并注意我添加了按 Date desc 的顺序来获取最近发送的数据

    select *
    from table1 a
    inner join table2 b on a.pID=b.pID
    where b.rowID in(select top(1) from table2 t where t.pID=a.pID order by Date desc)
    

    【讨论】:

    • 谢谢,我确实忘记了订单。但在执行时间它保持不变。
    • 为了提高索引字段所需的性能,我忘记将 rowID 放在 select 中(select top(1) rowID from table2 t...)
    【解决方案3】:

    我在类似的场景中使用下面的代码(我将其转录到您的示例中)

    SELECT b.*
    FROM table1 AS a
    left outer join (
        SELECT a.*
        FROM table2 a
            inner join (
                SELECT a.pID, max(date) as date 
                FROM table2
                WHERE date <= <max_date>
                group by pID
                ) b ON a.pID = b.pID AND a.date = b.date
            ) b ON a.pID = b.pID
    ) b on a.pID = b.pID
    

    这种方法的唯一问题是您必须确保日期不会重复 pID

    【讨论】:

      【解决方案4】:

      您可以使用row_number() 函数和子查询来做到这一点:

      SELECT t1.* 
      FROM table1 t1 LEFT JOIN
           (select t2.*, row_number() over (partition by pId order by rowId desc) as seqnum
            from table2 t2
           ) t2
           on t1.pId = t2.pId and t2.seqnum = 1;
      

      【讨论】:

      • 这样更快并且得到正确的结果。谢谢
      • @jvcoppen 。 . .你有理由不接受这个答案吗?你可以接受任何你喜欢的答案,但我更喜欢这种方法而不是当前接受的答案。
      【解决方案5】:

      使用 ROW_NUMBER() 函数获取一列,说明表 2 中每一行的哪个 id 是第一个(按 pID 分区,并按 rowDate 降序排序)

      例子:

      WITH cte AS 
      (
        SELECT 
          rowID AS t2RowId, 
          ROW_NUMBER OVER (PARTITION BY pID ORDER BY rowDate DESC) AS rowNum
        FROM table2 t2
      ) -- gets the t2RowIds + a column which says which is the latest for each pID
      SELECT t1.*, t2.* 
      FROM table1 t1
      LEFT JOIN 
      (
        table2 t2
        JOIN cte ON t2.rowID = cte.t2RowId AND cte.rowNum = 1
      ) ON t1.pID = t2.pID
      

      这保证每个 pID 仅返回 table2 中的 1 个项目,即使多个项目具有相同的日期。您当然应该确保在表 2 中对日期列进行索引,以便快速执行(理想情况下,索引还包括表 2 的 PrimaryID)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-10
        • 2015-01-09
        • 2021-11-09
        • 1970-01-01
        • 1970-01-01
        • 2013-07-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多