如何将此Select语句移至Top

时间:2014-05-16 16:25:42

标签: sql join subquery row-number

我尝试优化此查询以使用联接而不是此子查询,但使用Top 1时,我有点困惑。

SELECT
    s.ItemNumber
    s.ImportKey
    ,(
        SELECT top 1 MerchandiseGroupID 
        FROM MerchandiseGroup mg 
        WHERE s.StoreDepartment = mg.Name AND c.ClientNumber = s.ClientNumber
    ) as MerchandiseGroupID
FROM dbo.Source s 
INNER JOIN dbo.Client c on s.ClientNumber = c.ClientNumber
INNER JOIN dbo.ClientVendor cv on s.Vendor = cv.ClientVendorName
INNER JOIN dbo.TypeClientWarehouse tw on c.WarehouseCode = tw.WarehouseCode
WHERE s.ImportDate > '2014-05-15 01:00:00.000'

到目前为止我所拥有的:

INNER JOIN
(
    SELECT
        ROW_NUMBER() OVER (PARTITION BY Name ORDER BY MerchandiseGroupID asc) rnum,
        MerchandiseGroupID,
        Name 
    FROM MerchandiseGroup mg
) mhg
    ON s.StoreDepartment = mg.Name AND c.ClientNumber = s.ClientNumber
WHERE s.ImportDate > '2014-05-15 01:00:00.000' AND mg.rnum = 1

1 个答案:

答案 0 :(得分:1)

我认为使用TOP 1并不是最优于将其转换为连接并使用ROW_NUMBER(),但是如果您想要连接的原因是这样您可以从表中获取其他字段,那么使用APPLY (你的第一个查询没有顶部的顺序,所以我假设它与JOIN尝试中的ROW_NUMBER函数相同):

SELECT
    s.ItemNumber,
    s.ImportKey,
    mg.MerchandiseGroupID,
    mg.Name
FROM dbo.Source s 
INNER JOIN dbo.Client c on s.ClientNumber = c.ClientNumber
INNER JOIN dbo.ClientVendor cv on s.Vendor = cv.ClientVendorName
INNER JOIN dbo.TypeClientWarehouse tw on c.WarehouseCode = tw.WarehouseCode
OUTER APPLY
(
    SELECT top 1 MerchandiseGroupID, Name
    FROM MerchandiseGroup mg 
    WHERE s.StoreDepartment = mg.Name 
    AND c.ClientNumber = s.ClientNumber
    ORDER BY MerchandiseGroupID
) mg
WHERE s.ImportDate > '2014-05-15 01:00:00.000'

如果你只想要前1,这种方法往往比ROW_NUMBER更快,如果你想要特定的记录,它就不那么灵活了,例如第3条记录。

使用日期格式时没有相关性,但是很明显,即使这是ISO标准,它仍然会引发错误:

SET DATEFORMAT DMY;
SELECT  CAST('2014-05-15 01:00:00.000' AS DATETIME);

会给你:

  

Msg 242,Level 16,State 3,Line 2

     

将varchar数据类型转换为日期时间数据类型会导致超出范围的值。