如何在单个SQL查询上执行多个聚合

时间:2015-05-21 02:51:30

标签: sql sql-server stored-procedures

我有一个包含三列的表:

GEOID,ParcelID和PurchaseDate。

PK是GEOID和ParcelID,格式如下:

GEOID     PARCELID     PURCHASEDATE
12345     AB123        1/2/1932
12345     sfw123       2/5/2012
12345     fdf323       4/2/2015
12346     dfefej       2/31/2022 <-New GEOID

我需要的是基于GEOID的聚合。 我需要计算上个月PER GEOID的ParcelID数量 我需要提供上个月所有销售总额的GEOID百分比。

我需要制作三列: GEOID Nbr_Parcels_Sold Percent_of_total

对于每个GEOID,我需要知道上个月售出的包裹数量,并且根据该数量,找出所有销售所需的百分比。

例如:如果上个月有20个包裹被售出,其中4个从GEOID 12345出售,那么输出将是:

GEOID  Nbr_Parcels_Sold  Perc_Total
12345  4                   .2  (or 20%)

我遇到双重聚合问题。令人担忧的是,该表有超过800万条记录。

如果此前有一位SQL Warrior曾经见过这个问题,那么任何智慧都会受到高度赞赏。 感谢。

3 个答案:

答案 0 :(得分:2)

希望您使用的是SQL Server 2005或更高版本,在这种情况下,您可以利用windowed聚合。在这种情况下,窗口聚合将允许您获得总销售数和每GEOID的计数,并在计算中使用总计。基本上,以下查询只返回计数:

SELECT
  GEOID,
  Nbr_Parcels_Sold   = COUNT(*),
  Total_Parcels_Sold = SUM(COUNT(*)) OVER ()
FROM
  dbo.atable
GROUP BY
  GEOID
;

COUNT(*)调用根据GROUP BY子句为每个GEOID提供计数。现在,SUM(...) OVER表达式为您提供与详细计数在同一行中的总计数。它是空的OVER子句,它告诉SUM函数在整个结果集中添加COUNT(*)的结果。您可以在计算中使用该结果,就像任何其他函数(或一般的任何表达式)的结果一样。

上述查询只返回总值。由于您实际上不需要值本身,而是每个GEOID的百分比,您可以将SUM(...) OVER调用放入表达式中:

SELECT
  GEOID,
  Nbr_Parcels_Sold = COUNT(*),
  Percent_of_total = COUNT(*) * 100 / SUM(COUNT(*)) OVER ()
FROM
  dbo.atable
GROUP BY
  GEOID
;

以上将给出整数百分比(截断)。如果您想要更高的精度或不同的表示,请记住将除数或被除数(可选两者)转换为非整数数字类型,因为当两个操作数都是整数时,SQL Server始终执行积分除法。

答案 1 :(得分:1)

如何使用子查询来计算总和

WITH data AS
(
    SELECT *
    FROM [Table]
    WHERE
        YEAR(PURCHASEDATE) * 100 + MONTH(PURCHASEDATE) = 201505
)
SELECT 
    GEOID,
    COUNT(*) AS Nbr_Parcels_Sold,
    CONVERT(decimal(18,8), COUNT(*)) / 
        (SELECT COUNT(*) FROM data) AS Perc_Total
FROM 
    data t
GROUP BY
    GEOID

修改

要按结果更新其他表格,请使用UPDATE

下的WITH()
WITH data AS
(
    SELECT *
    FROM [Table]
    WHERE
        YEAR(PURCHASEDATE) * 100 + MONTH(PURCHASEDATE) = 201505
)
UPDATE target SET 
    Nbr_Parcels_Sold = source.Nbr_Parcels_Sold, 
    Perc_Total = source.Perc_Total
FROM 
    [AnotherTable] target
    INNER JOIN
    (
        SELECT 
            GEOID,
            COUNT(*) AS Nbr_Parcels_Sold,
            CONVERT(decimal(18,8), COUNT(*)) / 
                (SELECT COUNT(*) FROM data) AS Perc_Total
        FROM 
            data t
        GROUP BY
            GEOID
    ) source ON target.GEOID = source.GEOID

答案 2 :(得分:0)

尝试以下方法。它将总销售额计入变量,然后在后续查询中使用它:

DECLARE @pMonthStartDate DATETIME
DECLARE @MonthEndDate DATETIME
DECLARE @TotalPurchaseCount INT

SET @pMonthStartDate = <EnterFirstDayOfAMonth>

SET @MonthEndDate = DATEADD(MONTH, 1, @pMonthStartDate)

SELECT
  @TotalPurchaseCount = COUNT(*)
FROM
  GEOIDs
WHERE
  PurchaseDate BETWEEN @pMonthStartDate
               AND     @MonthEndDate 
SELECT
  GEOID,
  COUNT(PARCELID) AS Nbr_Parcels_Sold,
  CAST(COUNT(PARCELID) AS FLOAT) / CAST(@TotalPurchaseCount AS FLOAT) * 100.0 AS Perc_Total
FROM
  GEOIDs
WHERE
  ModifiedDate BETWEEN @pMonthStartDate
               AND     @MonthEndDate
GROUP BY
  GEOID

我猜你的表名是GEOIDs。更改@pMonthStartDate的值以适合自己。如果您的PK如您所说那么这将是一个快速查询。