You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

求助:将含多聚合表头的Access透视查询转换为MSSQL

Access透视查询转SQL Server实现方案

没问题!我帮你把Access的TRANSFORM透视查询转换成SQL Server的版本,专门解决你提到的「表头包含多个字段组合」的透视难题——核心思路是先把需要作为表头的多个字段拼接成单个列,再用透视语法实现。

先理清楚原查询逻辑

你的原Access查询是基于多张表关联,筛选2017年发货、排除特定分组、特定质量等级和数据集的记录,最终按ID_SaleDest作为行,聚合Tons的总和,同时用多个字段组合作为列表头(你原代码的PIVOT部分没写完,我假设是QualPackGroups的字段组合,你可以根据实际调整)。


方案1:静态透视(已知所有表头值)

如果提前知道所有要作为表头的字段组合值,可以直接写静态透视:

SELECT 
    ID_SaleDest,
    -- 这里替换成实际的表头组合值,比如[Q1-GroupA]、[Q2-GroupB]
    [Q1-GroupA] AS [Q1-GroupA_总吨数],
    [Q2-GroupB] AS [Q2-GroupB_总吨数]
FROM (
    -- 子查询:准备透视所需的基础数据,拼接表头字段
    SELECT 
        Sales.ID_SaleDest,
        -- 把需要作为表头的多个字段拼接成一个列,这里用QualPack和Groups的字段举例
        CONCAT(QualPack.QualityCode, '-', Groups.GroupName) AS PivotColumn,
        Sales.Tons
    FROM 
        QualPack
        INNER JOIN SaleDest ON QualPack.ID_QualPack = SaleDest.ID_QualPack
        INNER JOIN Groups ON Groups.ID_Group = SaleDest.ID_Group
        INNER JOIN Customers ON Customers.ID_Customer = SaleDest.ID_Customer
        INNER JOIN Sales ON SaleDest.ID_SaleDest = Sales.ID_SaleDest
    WHERE 
        YEAR(Sales.Date_shipped) = 2017
        AND SaleDest.ID_Group <> 10
        AND QualPack.Quality_Second <> 'NO'
        AND Sales.ID_Dataset IN ('AC', 'BU')
        -- 补充你原代码中未完成的WHERE条件
) AS SourceData
PIVOT (
    -- 对应Access的TRANSFORM SUM(Sales.Tons)
    SUM(Tons)
    -- 指定用拼接后的列作为透视表头
    FOR PivotColumn IN ([Q1-GroupA], [Q2-GroupB])
) AS PivotTable;

方案2:动态透视(表头值不确定)

如果表头的字段组合值是动态变化的,就需要用动态SQL自动生成列列表:

DECLARE @PivotColumns NVARCHAR(MAX);
DECLARE @SQL NVARCHAR(MAX);

-- 第一步:自动生成所有需要透视的列名(拼接后的字段组合)
SELECT @PivotColumns = STRING_AGG(QUOTENAME(CONCAT(QualPack.QualityCode, '-', Groups.GroupName)), ', ')
FROM 
    QualPack
    INNER JOIN SaleDest ON QualPack.ID_QualPack = SaleDest.ID_QualPack
    INNER JOIN Groups ON Groups.ID_Group = SaleDest.ID_Group
    INNER JOIN Customers ON Customers.ID_Customer = SaleDest.ID_Customer
    INNER JOIN Sales ON SaleDest.ID_SaleDest = Sales.ID_SaleDest
WHERE 
    YEAR(Sales.Date_shipped) = 2017
    AND SaleDest.ID_Group <> 10
    AND QualPack.Quality_Second <> 'NO'
    AND Sales.ID_Dataset IN ('AC', 'BU')
GROUP BY 
    QualPack.QualityCode, Groups.GroupName;

-- 第二步:构建动态SQL语句
SET @SQL = N'
SELECT 
    ID_SaleDest,
    ' + @PivotColumns + '
FROM (
    SELECT 
        Sales.ID_SaleDest,
        CONCAT(QualPack.QualityCode, ''-'', Groups.GroupName) AS PivotColumn,
        Sales.Tons
    FROM 
        QualPack
        INNER JOIN SaleDest ON QualPack.ID_QualPack = SaleDest.ID_QualPack
        INNER JOIN Groups ON Groups.ID_Group = SaleDest.ID_Group
        INNER JOIN Customers ON Customers.ID_Customer = SaleDest.ID_Customer
        INNER JOIN Sales ON SaleDest.ID_SaleDest = Sales.ID_SaleDest
    WHERE 
        YEAR(Sales.Date_shipped) = 2017
        AND SaleDest.ID_Group <> 10
        AND QualPack.Quality_Second <> ''NO''
        AND Sales.ID_Dataset IN (''AC'', ''BU'')
        -- 补充你原代码中未完成的WHERE条件
) AS SourceData
PIVOT (
    SUM(Tons)
    FOR PivotColumn IN (' + @PivotColumns + ')
) AS PivotTable;';

-- 执行动态SQL
EXEC sp_executesql @SQL;

关键注意事项

  1. 表头字段调整:如果原Access的PIVOT是单个字段而非组合,直接把CONCAT(...)换成对应的单个字段即可(比如QualPack.QualityCode)。
  2. 旧版本SQL Server兼容:如果你的SQL Server版本低于2017,STRING_AGG不支持,需要用FOR XML PATH来生成列列表,替换第一步的代码即可。
  3. 未完成的WHERE条件:你原代码里的WHERE ((( Year([Date_shipped]))=2017) ... OR ((( Year([Date_...没写完,记得把剩余条件补充到两个方案的WHERE子句中。
  4. 单引号转义:动态SQL里的单引号需要用两个单引号''表示,避免语法错误。

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

火山引擎 最新活动