【问题标题】:LEFT OUTER JOIN and only return the first matchLEFT OUTER JOIN 并且只返回第一个匹配
【发布时间】:2016-03-15 16:57:06
【问题描述】:

想象以下两个表,分别命名为“Users”和“Orders”:

ID  NAME
1   Foo
2   Bar
3   Qux


ID  USER  ITEM  SPEC  TIMESTAMP
1   1     12    4     20150204102314
2   1     13    6     20151102160455
3   3     25    9     20160204213702

我想得到的输出是:

USER   ITEM  SPEC  TIMESTAMP
1      12    4     20150204102314
2      NULL  NULL  NULL
3      25    9     20160204213702

换句话说:在用户和订单之间进行 LEFT OUTER JOIN,如果您没有找到该用户的任何订单,则返回 null,但如果您确实找到了一些,则只返回第一个(基于最早的时间戳)。

如果我只使用 LEFT OUTER JOIN,它将为用户 1 返回两行,我不希望这样。我想将 LEFT OUTER JOIN 嵌套在另一个选择中,该选择将 GROUP BY 其他字段并获取 MIN(TIMESTAMP) 但这也不起作用,因为我需要在我的 group by 中有“SPEC”,并且因为这两个订单有不同的 SPEC,它们仍然会出现。

感谢任何关于如何达到预期结果的想法。

【问题讨论】:

    标签: sql sql-server left-join outer-join


    【解决方案1】:

    我能想到的最好方法是使用OUTER APPLY

    SELECT *
    FROM   Users u
           OUTER apply (SELECT TOP 1 *
                        FROM   Orders o
                        WHERE  u.ID = o.[USER]
                        ORDER  BY TIMESTAMP DESC) ou
    

    另外在ORDERS 表上创建一个低于NON-Clustered 的索引将帮助您提高查询的性能

    CREATE NONCLUSTERED INDEX IX_ORDERS_USER
      ON ORDERS ([USER], TIMESTAMP)
      INCLUDE ([ITEM], [SPEC]); 
    

    【讨论】:

      【解决方案2】:

      这应该可以解决问题:

      SELECT  Users.ID, Orders2.USER ,  Orders2.ITEM ,  Orders2.SPEC ,  Orders2.TIMESTAMP
      FROM    Users
      LEFT JOIN 
              (
              SELECT  Orders.ID, Orders.USER ,  Orders.ITEM ,  Orders.SPEC ,  Orders.TIMESTAMP, ROW_NUMBER()
                      OVER (PARTITION BY ID  ORDER BY TIMESTAMP DESC) AS RowNum
              FROM    Orders
      
              ) Orders2 ON Orders2.ID = Users.ID And RowNum = 1
      

      【讨论】:

        【解决方案3】:

        另一种方法是使用窗口函数作为 Cte:

        with Sorted as
        (
          select u.id as User, o.Item, o.Spec, o.Timestamp
                 row_number() over (partition by u.Id order by Timestamp) as Row
            from Users u
            left join orders o
              on o.User = u.Id
        )
        select User, Item, Spec, Timestamp
          from Sorted where Row = 1
        

        【讨论】:

          【解决方案4】:

          您会在this question 中找到很多建议。你有一个左连接的事实对于你想要做的事情真的很偶然,所以这些答案应该很容易适应你的问题。我同意@MotoGP 的观点,对于 SQLServer,OUTER APPLY 可能是最好的方法。它与 Postgres 的 LATERAL JOIN 非常相似(在另一个链接中提到)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-09-30
            • 1970-01-01
            • 2022-01-01
            • 1970-01-01
            • 2013-11-18
            • 1970-01-01
            • 1970-01-01
            • 2013-03-26
            相关资源
            最近更新 更多