重用SQL中的SUB查询列

时间:2014-02-26 12:06:54

标签: sql sql-server-2012

我有以下SQL,

SELECT  U.ID AS UserID
    ,U.LoginName AS Name
    ,PV.Time AS [Time]
    ,PV.URL AS [Url]
    ,P.Name AS [Product 1 Name]
    ,P.SKU AS [Product 1 SKU]
    ,P.ModelNumber AS [Product 1 Model Number]
    ,P2.Name AS [Product 2 Name]
    ,P2.SKU AS [Product 2 SKU]
    ,P2.ModelNumber AS [Product 2 Model Number]
    ,ISNULL((select TOP 1 Value from AttributesValues AV INNER JOIN Attributes A ON AV.AttributeID = A.ID WHERE AV.ProductID = P.ID AND A.RetailerID = 23 AND A.CODE = 'metadata-department'),'') AS Department
        ,ISNULL((select TOP 1 Value from AttributesValues AV INNER JOIN Attributes A ON AV.AttributeID = A.ID WHERE AV.ProductID = P.ID AND A.RetailerID = 23 AND A.CODE = 'metadata-group'),'') AS Department
        ,ISNULL((select TOP 1 Value from AttributesValues AV INNER JOIN Attributes A ON AV.AttributeID = A.ID WHERE AV.ProductID = P.ID AND A.RetailerID = 23 AND A.CODE = 'metadata-subgroup'),'') AS SubGroup
        ,C.Browser AS [Browser]
        ,C.BrowserVersion AS [Browser Version]
        ,C.IPAddress AS [IP Address]
        ,C.UserAgent AS [User Agent]
        ,C.UserLanguage AS [User Language]
        ,PV.PageType AS [Page Type]
FROM    PageVisits PV
        INNER JOIN Users U ON U.ID = PV.UserID
        INNER JOIN Clients C ON C.ID = PV.ClientID
        INNER JOIN Products P ON P.id = PV.P1ID 
        LEFT OUTER JOIN Products P2 ON P2.id = PV.P2ID 
WHERE   P.RetailerID = 23 
        AND PV.UserID IS NOT NULL
        AND PV.PageType IN ('Product','Compare Products')
        AND PV.[Time] >= '{0}' AND PV.[Time] < '{1}'

问题是这个子查询,

,ISNULL((select TOP 1 Value from AttributesValues AV 
 INNER JOIN Attributes A ON AV.AttributeID = A.ID 
 WHERE AV.ProductID = P.ID AND A.RetailerID = 23 
 AND A.CODE = 'metadata-department'),'') AS Department

我在这里用了3次。唯一的区别是A.CODE =。我怎样才能改善这个

3 个答案:

答案 0 :(得分:3)

您应该首先尝试为查询构建索引:

create index on Attributes(RetailerId, Code, Id);
create index on AttributeValues(AttributeId, ProductId, Value);

子查询的处理应该只是几个索引查找。

答案 1 :(得分:2)

始终将ORDER BYTOP一起使用。否则,您将获得不确定的结果,具体取决于SQL引擎将如何获取相关行。

如果确实不需要TOP 1,即如果子查询总是返回1(或0)行而没有TOP,那么您可以将OUTER APPLYMAX()一起使用:

SELECT
    ---
        ,COALESCE(X.Department, '') AS Department
        ,COALESCE(X.[Group], '')    AS [Group]
        ,COALESCE(X.SubGroup, '')   AS SubGroup
    ---
FROM    PageVisits PV
        INNER JOIN Users U ON U.ID = PV.UserID
        INNER JOIN Clients C ON C.ID = PV.ClientID
        INNER JOIN Products P ON P.id = PV.P1ID 
        LEFT OUTER JOIN Products P2 ON P2.id = PV.P2ID 
        OUTER APPLY
        ( SELECT   MAX(CASE WHEN A.CODE = 'metadata-department' THEN AV.Value END) 
                      AS Department
                  ,MAX(CASE WHEN A.CODE = 'metadata-group' THEN AV.Value END) 
                      AS [Group]
                  ,MAX(CASE WHEN A.CODE = 'metadata-subqroup' THEN AV.Value END) 
                      AS SubGroup
          FROM    AttributesValues AV 
                  INNER JOIN Attributes A ON AV.AttributeID = A.ID 
          WHERE   AV.ProductID = P.ID 
            AND   A.RetailerID = 23 
        ) X
WHERE   
    --- ;

答案 2 :(得分:1)

你可以定义一个CTE,它基本上是一个内联视图,以避免重新输入查询,但它实际上不会改变正在执行3次的查询,它只会整理代码:

WITH CTE AS
(   SELECT  AV.ProductID, AV.Value, A.Code 
    FROM    AttributesValues AV 
            INNER JOIN Attributes A ON AV.AttributeID = A.ID 
    WHERE   A.RetailerID = 23
)
SELECT  U.ID AS UserID
        ,U.LoginName AS Name
        ,PV.Time AS [Time]
        ,PV.URL AS [Url]
        ,P.Name AS [Product 1 Name]
        ,P.SKU AS [Product 1 SKU]
        ,P.ModelNumber AS [Product 1 Model Number]
        ,P2.Name AS [Product 2 Name]
        ,P2.SKU AS [Product 2 SKU]
        ,P2.ModelNumber AS [Product 2 Model Number]
        ,ISNULL((SELECT TOP 1 Value FROM CTE WHERE CTE.ProductID = P.ID AND CTE.CODE = 'metadata-department'),'') AS Department
        ,ISNULL((SELECT TOP 1 Value FROM CTE WHERE CTE.ProductID = P.ID AND CTE.CODE = 'metadata-group'),'') AS [Group]
        ,ISNULL((SELECT TOP 1 Value FROM CTE WHERE CTE.ProductID = P.ID AND CTE.CODE = 'metadata-subgroup'),'') AS SubGroup
        ,C.Browser AS [Browser]
        ,C.BrowserVersion AS [Browser Version]
        ,C.IPAddress AS [IP Address]
        ,C.UserAgent AS [User Agent]
        ,C.UserLanguage AS [User Language]
        ,PV.PageType AS [Page Type]
FROM    PageVisits PV
        INNER JOIN Users U ON U.ID = PV.UserID
        INNER JOIN Clients C ON C.ID = PV.ClientID
        INNER JOIN Products P ON P.id = PV.P1ID 
        LEFT OUTER JOIN Products P2 ON P2.id = PV.P2ID 
WHERE   P.RetailerID = 23 
        AND PV.UserID IS NOT NULL
        AND PV.PageType IN ('Product','Compare Products')
        AND PV.[Time] >= '{0}' AND PV.[Time] < '{1}'

值得注意的是,TOP 1没有订单,这会给你带来不确定的结果(除非有唯一的约束来确保只有一行可以返回)。

我也倾向于将其重写为JOIN以减少AttributesValuesAttributes上的表读取次数。您可以通过在属性值上使用PIVOT来执行此操作:

WITH CTE AS
(   SELECT  AV.ProductID, 
            AV.Value, 
            A.Code ,
            RowNumber = ROW_NUMBER() OVER(PARTITION BY AV.ProductID, A.Code ORDER BY AV.Value)
    FROM    AttributesValues AV 
            INNER JOIN Attributes A ON AV.AttributeID = A.ID 
    WHERE   A.RetailerID = 23
    AND     AV.Code IN ('metadata-department', 'metadata-group', 'metadata-subgroup')
), AV AS
(   SELECT  pvt.ProductID, 
            pvt.[metadata-department], 
            pvt.[metadata-group], 
            pvt.[metadata-subgroup]
    FROM    CTE
            PIVOT
            (   MAX(Value)
                FOR Code IN ([metadata-department], [metadata-group], [metadata-subgroup])
            ) pvt
    WHERE   pvt.RowNumber = 1
)
SELECT  U.ID AS UserID
        ,U.LoginName AS Name
        ,PV.Time AS [Time]
        ,PV.URL AS [Url]
        ,P.Name AS [Product 1 Name]
        ,P.SKU AS [Product 1 SKU]
        ,P.ModelNumber AS [Product 1 Model Number]
        ,P2.Name AS [Product 2 Name]
        ,P2.SKU AS [Product 2 SKU]
        ,P2.ModelNumber AS [Product 2 Model Number]
        ,ISNULL(AV.[metadata-department],'') AS Department
        ,ISNULL(AV.[metadata-group],'') AS [Group]
        ,ISNULL(AV.[metadata-subgroup],'') AS SubGroup
        ,C.Browser AS [Browser]
        ,C.BrowserVersion AS [Browser Version]
        ,C.IPAddress AS [IP Address]
        ,C.UserAgent AS [User Agent]
        ,C.UserLanguage AS [User Language]
        ,PV.PageType AS [Page Type]
FROM    PageVisits PV
        INNER JOIN Users U ON U.ID = PV.UserID
        INNER JOIN Clients C ON C.ID = PV.ClientID
        INNER JOIN Products P ON P.id = PV.P1ID 
        LEFT OUTER JOIN Products P2 ON P2.id = PV.P2ID 
        LEFT OUTER JOIN AV ON AV.ProductID = p.ID
WHERE   P.RetailerID = 23 
        AND PV.UserID IS NOT NULL
        AND PV.PageType IN ('Product','Compare Products')
        AND PV.[Time] >= '{0}' AND PV.[Time] < '{1}'

N&gt; B 您可能希望更改ORDER BY中的ROW_NUMBER,以影响针对productID和Code的每个组合返回的值(如果这是唯一的虽然顺序是无关紧要的)*