2

此查询来自“Microsoft SQL Server 2008 - 数据库开发”(如果您有这本书,请参见第 26 页)。而且,由于在本书中找到了查询,因此我正在针对 AdventureWorks2008 数据库运行。问题是由发布的第一个查询引起的,但是下面有第二个查询和解决方法。

问题:当使用 WITH ROLLUP 和 HAVING 子句时,为什么我们缺少 ProductCategoryID = 2 的小计行,以及以下查询中的总计行?

在删除 HAVING 子句时,所有 ProductCategoryID 都有一个小计行,并且一个总计行包含在结果集中。

询问:

SELECT
    Production.ProductCategory.ProductCategoryID
    , Production.Product.ProductSubcategoryID
    , AVG(ListPrice) AS 'Average'
    , MIN(ListPrice) AS 'Minimum'
    , MAX(ListPrice) AS 'Maximum'
FROM Production.Product
JOIN Production.ProductSubcategory ON Production.ProductSubcategory.ProductSubcategoryID = Production.Product.ProductSubcategoryID
JOIN Production.ProductCategory ON Production.ProductSubcategory.ProductCategoryID = Production.ProductCategory.ProductCategoryID
WHERE
    ListPrice <> 0
GROUP BY
    Production.ProductCategory.ProductCategoryID
    , Production.Product.ProductSubcategoryID
WITH ROLLUP
HAVING
    MIN(ListPrice) > 200

结果:

ProductCategoryId   ProductSubcategoryId    Average     Minimum Maximum
1                   1                       1683.365    539.99  3399.99
1                   2                       1597.45     539.99  3578.27
1                   3                       1425.2481   742.35  2384.07
1                   NULL                    1586.737    539.99  3578.27
2                   12                      678.2535    249.79  1364.50
2                   14                      780.0436    337.22  1431.50
2                   16                      631.4155    333.42  1003.91

以我期望在原始查询中看到的结果结束的查询(通过用子查询替换我们的 HAVING 子句来解决问题):

SELECT
    Production.ProductCategory.ProductCategoryID
    , Production.Product.ProductSubcategoryID
    , AVG(ListPrice) AS 'Average'
    , MIN(ListPrice) AS 'Minimum'
    , MAX(ListPrice) AS 'Maximum'
FROM Production.Product
JOIN Production.ProductSubcategory ON Production.ProductSubcategory.ProductSubcategoryID = Production.Product.ProductSubcategoryID
JOIN Production.ProductCategory ON Production.ProductSubcategory.ProductCategoryID = Production.ProductCategory.ProductCategoryID
WHERE
    ListPrice <> 0
    AND Production.Product.ProductSubcategoryID IN 
    (
        SELECT
            Production.Product.ProductSubcategoryID
        FROM Production.Product
        GROUP BY
            Production.Product.ProductSubcategoryID
        HAVING
            MIN(ListPrice) > 200
    )
GROUP BY
    Production.ProductCategory.ProductCategoryID
    , Production.Product.ProductSubcategoryID
WITH ROLLUP

结果:

ProductCategoryId   ProductSubcategoryId    Average     Minimum Maximum
1                   1                       1683.365    539.99  3399.99
1                   2                       1597.45     539.99  3578.27
1                   3                       1425.2481   742.35  2384.07
1                   NULL                    1586.737    539.99  3578.27
2                   12                      678.2535    249.79  1364.50
2                   14                      780.0436    337.22  1431.50
2                   16                      631.4155    333.42  1003.91
2                   NULL                    710.1015    249.79  1431.50
NULL                NULL                    1193.2472   249.79  3578.27
4

2 回答 2

1

我同意“这些行丢失,因为 HAVING 子句是在 ROLLUP 子句之后应用的”。取回行的一种方法是将 HAVING 子句从以下位置更改:

HAVING
     MIN(ListPrice) > 200

至:

HAVING
     (MIN(ListPrice) > 200)
  or (Grouping (Production.ProductCategory.ProductCategoryID) = 1)
  or (Grouping (Production.Product.ProductSubcategoryID) =  1)

此外,应该有一个订单条款。就像是:

Order by Case
            When (Grouping (Production.ProductCategory.ProductCategoryID) = 1) Then 1
            Else 0
            End,
         Production.ProductCategory.ProductCategoryID,
         Case
            When (Grouping (Production.Product.ProductSubcategoryID) =  1) Then 1
            Else 0
            End,
         Production.Product.ProductSubcategoryID
于 2015-10-17T21:43:53.127 回答
0

缺少这些行是因为在 ROLLUP 子句之后应用了 HAVING 子句,并且这些行的 MIN(ListPrice) 小于 200(ProductSubcategoryId ProductCategoryId 2 的总和为 20.24,总计为 2.29)。

要获得与第二个查询相同的结果,您还可以使用:

SELECT
    c.ProductCategoryID
    , s.ProductSubcategoryID
    , AVG(ListPrice) AS 'Average'
    , MIN(ListPrice) AS 'Minimum'
    , MAX(ListPrice) AS 'Maximum'
FROM (
    SELECT *, MIN(ListPrice) OVER (PARTITION BY ProductSubcategoryID) AS MinimumListPriceForSubcategory
    FROM Production.Product
) p
JOIN Production.ProductSubcategory s ON s.ProductSubcategoryID = p.ProductSubcategoryID
JOIN Production.ProductCategory c ON s.ProductCategoryID = c.ProductCategoryID
WHERE ListPrice <> 0
AND MinimumListPriceForSubcategory>200
GROUP BY c.ProductCategoryID, s.ProductSubcategoryID
WITH ROLLUP
于 2012-12-22T09:44:43.217 回答