You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AdventureWorks数据库TSQL问题:按地区统计销售额及销售人员数排查

TSQL PIVOT 分组问题的解决方案

嘿,这个问题我太熟了!你现在的代码之所以会为每个销售人员生成单独行,核心原因是没有先对数据按销售地区和年份做预聚合——直接拿包含单个销售记录的原始数据去做PIVOT,PIVOT会把所有未被聚合的字段(比如销售人员ID)当成分组维度,自然就拆成了每行对应一个销售的结果。

要实现你想要的“按地区分组、展示各年度销售额+地区活跃销售人数”的效果,得分成两步走:先聚合数据,再做透视。下面给你两种可行的实现方案,都是基于AdventureWorks数据库的表结构来写的:

方案一:用CTE整合聚合与透视

WITH SalesTerritoryAggregates AS (
    -- 第一步:统计各地区的活跃销售人员数量
    SELECT 
        st.Name AS SalesTerritory,
        COUNT(DISTINCT sp.BusinessEntityID) AS SalesPeople,
        NULL AS OrderYear,
        NULL AS AnnualSales
    FROM Sales.SalesPerson sp
    JOIN Sales.SalesTerritory st ON sp.TerritoryID = st.TerritoryID
    GROUP BY st.Name

    UNION ALL

    -- 第二步:统计各地区各年度的销售总额
    SELECT 
        st.Name AS SalesTerritory,
        NULL AS SalesPeople,
        YEAR(soh.OrderDate) AS OrderYear,
        SUM(soh.TotalDue) AS AnnualSales
    FROM Sales.SalesOrderHeader soh
    JOIN Sales.SalesTerritory st ON soh.TerritoryID = st.TerritoryID
    GROUP BY st.Name, YEAR(soh.OrderDate)
),
PivotReadyData AS (
    -- 把销售人数关联到每一行年度数据上,确保透视后每个地区只有一行
    SELECT 
        SalesTerritory,
        MAX(SalesPeople) OVER (PARTITION BY SalesTerritory) AS SalesPeople,
        OrderYear,
        AnnualSales
    FROM SalesTerritoryAggregates
    WHERE OrderYear IS NOT NULL
)
-- 执行透视,得到目标格式
SELECT 
    SalesTerritory,
    SalesPeople,
    [2011], [2012], [2013], [2014]
FROM PivotReadyData
PIVOT (
    SUM(AnnualSales)
    FOR OrderYear IN ([2011], [2012], [2013], [2014])
) AS PivotResult
ORDER BY SalesTerritory;

方案二:分开处理再关联(可读性更强)

这个方案把“销售总额透视”和“销售人数统计”拆成两个独立的CTE,最后关联起来,逻辑更清晰:

-- 先生成各地区各年度销售额的透视表
WITH PivotedSalesData AS (
    SELECT 
        st.Name AS SalesTerritory,
        [2011], [2012], [2013], [2014]
    FROM (
        SELECT 
            st.Name,
            YEAR(soh.OrderDate) AS OrderYear,
            soh.TotalDue
        FROM Sales.SalesOrderHeader soh
        JOIN Sales.SalesTerritory st ON soh.TerritoryID = st.TerritoryID
    ) AS SourceData
    PIVOT (
        SUM(TotalDue)
        FOR OrderYear IN ([2011], [2012], [2013], [2014])
    ) AS PivotTable
),
-- 统计各地区的活跃销售人员数量
SalesPeopleByTerritory AS (
    SELECT 
        st.Name AS SalesTerritory,
        COUNT(DISTINCT sp.BusinessEntityID) AS SalesPeople
    FROM Sales.SalesPerson sp
    JOIN Sales.SalesTerritory st ON sp.TerritoryID = st.TerritoryID
    GROUP BY st.Name
)
-- 关联两个结果集,得到最终格式
SELECT 
    psd.SalesTerritory,
    spt.SalesPeople,
    psd.[2011], psd.[2012], psd.[2013], psd.[2014]
FROM PivotedSalesData psd
JOIN SalesPeopleByTerritory spt ON psd.SalesTerritory = spt.SalesTerritory
ORDER BY psd.SalesTerritory;

关键要点总结

  • 必须先按目标分组维度(销售地区、年份)做聚合,把原始的行级销售记录转换成每个分组的汇总数据,再进行PIVOT操作。
  • 销售人数是地区维度的统计值,不是年度的,所以要单独聚合后再和透视后的销售额数据关联,或者用窗口函数把它映射到每一行年度数据上。

内容的提问来源于stack exchange,提问作者Vesper Annstas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:56:37