多次加入同一个表时的条件连接和查询优化

时间:2013-11-19 01:37:48

标签: sql sql-server query-optimization

我们的数据库中有两个表。有问题的查询中的主表是Asset。它与名为AssetListing的表有一对多的关系。 AssetListing表中包含多个日期和数字字段,我们当前有一个报表设置为获取每个日期之一,在某些情况下,还有AssetListing表中日期不为空的数值。需要注意的是,我们希望在特定日期不为空的情况下获取与最新AssetListingId(AssetListing上的PK)相关联的日期。查询目前如下所示:

SELECT A.AssetNumber
        , CLP.CurrentListPrice
, CLP.CurrentListPriceDate
, ListingExpirationDate = LXP.ExpirationDate
, LPC.ListPriceChange
, LPC.ListPriceChangeDate
FROM Asset A
LEFT JOIN
    (
        SELECT AssetNumber
            , AssetListingId
            , CurrentListPrice
            , CurrentListPriceDate
            , ROW_Num = ROW_NUMBER() OVER (PARTITION BY AssetNumber ORDER BY AssetListingId DESC)
        FROM [dbo].AssetListing WITH (NOLOCK)
        WHERE CurrentListPrice IS NOT NULL
    ) CLP ON CLP.AssetNumber = A.AssetNumber AND CLP.ROW_NUM = 1
LEFT JOIN
    (
        SELECT AssetNumber
            , AssetListingId
            , ExpirationDate
            , ROW_Num = ROW_NUMBER() OVER (PARTITION BY AssetNumber ORDER BY AssetListingId DESC)
        FROM [dbo].AssetListing WITH (NOLOCK)
        WHERE ExpirationDate IS NOT NULL
    ) LXP ON LXP.AssetNumber = A.AssetNumber AND LXP.ROW_NUM = 1
LEFT JOIN
    (
        SELECT AssetNumber
            , AssetListingId
            , CurrentListPrice
            , ListPriceChange
            , ListPriceChangeDate
            , ROW_Num = ROW_NUMBER() OVER (PARTITION BY AssetNumber ORDER BY AssetListingId DESC)
        FROM [dbo].AssetListing WITH (NOLOCK)
        WHERE ListPriceChange IS NOT NULL
    ) LPC ON LPC.AssetNumber = A.AssetNumber AND LPC.ROW_NUM = 1

必须有一种方法可以通过单个连接执行此操作,但我不确定如何执行此操作。 我们需要来自每个连接的日期,在某些情况下,我们还需要一个数值。 如何优化此查询?

1 个答案:

答案 0 :(得分:1)

试试这个,我们的想法是根据行号获取每个资产编号应该只有一个结果的最大值。

SELECT A.AssetNumber
    , CurrentListPrice      = MAX(CASE WHEN CPRN = 1 THEN CurrentListPrice END)
    , CurrentListPriceDate  = MAX(CASE WHEN CPRN = 1 THEN CurrentListPriceDate END)
    , ListingExpirationDate = MAX(CASE WHEN EPRN = 1 THEN ExpirationDate END)
    , ListPriceChange       = MAX(CASE WHEN EPRN = 1 THEN ExpirationDate END)
    , ListPriceChangeDate   = MAX(CASE WHEN EPRN = 1 THEN ExpirationDate END)
FROM Asset A
JOIN (
    SELECT AssetNumber
        , AssetListingId
        , CurrentListPrice
        , CurrentListPriceDate
        , ExpirationDate
        , ListPriceChange
        , ListPriceChangeDate
        , CPRN = CASE WHEN CurrentListPrice IS NOT NULL 
                      THEN ROW_NUMBER() OVER (PARTITION BY AssetNumber ORDER BY AssetListingId DESC) END
        , EPRN = CASE WHEN ExpirationDate IS NOT NULL 
                      THEN ROW_NUMBER() OVER (PARTITION BY AssetNumber ORDER BY AssetListingId DESC) END
        , LPRN = CASE WHEN ListPriceChange IS NOT NULL 
                      THEN ROW_NUMBER() OVER (PARTITION BY AssetNumber ORDER BY AssetListingId DESC) END
    FROM dbo.AssetListing WITH (NOLOCK)
) AL ON AL.AssetNumber = A.AssetNumber
GROUP BY A.AssetNumber

此处的连接实际上看起来并不是必要的,但我已将其保留,以防万一有简化。