【问题标题】:Joining top records in T-SQL连接 T-SQL 中的顶级记录
【发布时间】:2011-10-24 06:39:48
【问题描述】:
SELECT MD.*, Contact.FirstName 
FROM MerchantData MD
JOIN Merchant M ON M.MerchID = MD.MerchID   
JOIN (SELECT TOP 1 * FROM Location WHERE Location.BusID = MD.BusID) L ON L.BusID=MD.BusID
AND L.Deleted = 0
JOIN Contact ON Contact.ContactID = L.PrincipalID

我正在使用 SQLSERVER 2008 并尝试编写此 SQL 语句。有时,busid 有多个位置,我只想加入第一个找到的位置。我在“Location.BusID = MD.BusID”部分出现错误,因为 MD.BusID 无法绑定。是否可以在此连接的嵌套选择语句中使用 MD 表,或者是否有其他方法可以完成此操作?

我打算将使用嵌套查询的数据放在列列表中,以便在那里直接获取联系人数据。

【问题讨论】:

    标签: sql tsql join


    【解决方案1】:

    我认为拥有完整结果集的子查询会更简单:

    SELECT MD.*, Contact.FirstName 
    FROM MerchantData MD
    JOIN Merchant M ON M.MerchID = MD.MerchID   
    JOIN (SELECT BusID, MAX(PrincipalID)
          FROM Location
          WHERE Deleted = 0
          GROUP BY BusID) L ON L.BusID=MD.BusID
    JOIN Contact ON Contact.ContactID = L.PrincipalID
    

    JOIN 中的每个 BusID 仍然有一条记录,但它不相关。

    【讨论】:

    • 问题是MAX和第一个不一样
    • 他只想要一个BusID 并且没有指定排序顺序。如果他愿意,添加排序标准很简单。
    • @JNK 问题是在这种情况下要求最大删除将不起作用,因为子选择后的 L.Deleted = 0
    • @t-clausen - 很好,我会更正查询。我们可以把这个条件放在内部选择上。
    • 问题有同样的问题shug。看来你只是继承了它。
    【解决方案2】:
    SELECT MD.*, Contact.FirstName  
    FROM MerchantData MD 
    JOIN Merchant M ON M.MerchID = MD.MerchID    
    CROSS APPLY (SELECT TOP 1 * FROM Location WHERE BusID = MD.BusID AND DELETED = 0) L
    JOIN Contact ON Contact.ContactID = L.PrincipalID 
    

    【讨论】:

      【解决方案3】:

      这是“每组前 n 个”问题的案例。这个问题将指导你:

      SQL Server query select 1 from each sub-group

      你会想做这样的事情:

      SELECT MD.* ,
             Contact.FirstName 
      FROM MerchantData MD
      JOIN Merchant     M ON M.MerchID = MD.MerchID   
      JOIN ( select * ,
                    seq = rank() over( partition by BusID order by BusID , ... )
             from Location
             where L.Deleted = 0
           ) L on L.BusID = MD.BusID
              and seq     = 1
      JOIN Contact ON Contact.ContactID = L.PrincipalID
      

      虚拟表表达式应​​为每个 BusID 最多返回 1 个位置(如果 BusID 没有未删除的位置,则为 0)。

      【讨论】:

      • 规定的要求是先看再删,和先删不一样。但是您的解决方案很优雅,并且您确实清楚地说明了它的作用。
      【解决方案4】:

      为了尝试找出我会尝试的错误。看看它是否可以匹配 Location.BusID = MD.BusID。

          SELECT MD.*, Contact.FirstName 
          FROM MerchantData MD
          JOIN Merchant M ON M.MerchID = MD.MerchID   
          JOIN Location On Location.BusID = MD.BusID 
      

      你不用*所以用

          SELECT TOP 1 Location.BusID FROM Location WHERE Location.BusID = MD.BusID 
      

      一旦你的语法工作。

      您确实知道,一旦您开始使用它,它只会匹配“第一”行,然后检查它是否被删除。问题是没有“第一”行的顺序是任意的。即使表上有聚集索引,如果没有 order by 子句,也无法保证排序。要获得可重复的答案,您需要排序。但是,如果您正在排序并且只想要顶行,那么 MAX 或 MIN 和一个组会更直接。

      如果您只希望有一个或多个已删除位置的企业,那么以下方法应该可行,但您需要为分组依据细分列。如果两个删除的位置有不同的联系人姓名,那么它将分别报告。所以,这可能不是您想要的。

          SELECT MD.col1, MD.col2, Contact.FirstName 
          FROM MerchantData MD
          JOIN Merchant M ON M.MerchID = MD.MerchID   
          JOIN Location L
             ON  L.BusID = MD.BusID
             AND L.Deleted = 0
          JOIN Contact ON Contact.ContactID = L.PrincipalID 
          GROUP BY MD.col1, MD.col2, Contact.FirstName 
      

      【讨论】:

        猜你喜欢
        • 2022-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-19
        • 2012-03-01
        • 2011-02-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多