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

如何格式化SQL Server表数据以生成员工项目分配报表?

SQL Server宽表转窄表实现月度分配数据格式转换

针对你提供的test表(对应原Staff Allocation表),需要将横向的月份列转换为纵向的年月维度记录,以下提供三种实用实现方式:


方法一:UNION ALL手动拆分(直观易理解)

适合月份列数量较少的场景,直接将每个月份列拆分为独立行后合并:

SELECT
    StaffID,
    ProjectID,
    '2020-01' AS YearMonth,
    Jan20 AS Allocation
FROM test
UNION ALL
SELECT
    StaffID,
    ProjectID,
    '2020-02' AS YearMonth,
    Feb20 AS Allocation
FROM test
UNION ALL
SELECT
    StaffID,
    ProjectID,
    '2020-03' AS YearMonth,
    Mar20 AS Allocation
FROM test
UNION ALL
SELECT
    StaffID,
    ProjectID,
    '2020-04' AS YearMonth,
    Apr20 AS Allocation
FROM test
UNION ALL
SELECT
    StaffID,
    ProjectID,
    '2020-05' AS YearMonth,
    May20 AS Allocation
FROM test
UNION ALL
SELECT
    StaffID,
    ProjectID,
    '2020-06' AS YearMonth,
    Jun20 AS Allocation
FROM test
UNION ALL
SELECT
    StaffID,
    ProjectID,
    '2020-07' AS YearMonth,
    Jul20 AS Allocation
FROM test
-- 若有更多月份列,继续添加对应UNION ALL语句
ORDER BY StaffID, ProjectID, YearMonth;

方法二:UNPIVOT运算符(简洁高效)

利用SQL Server内置的UNPIVOT运算符直接实现列转行,同时处理列名到标准年月格式的转换:

SELECT
    StaffID,
    ProjectID,
    -- 将Jan20这类列名转换为'2020-01'格式的年月标识
    CONCAT('20', RIGHT(MonthCol, 2), '-', 
        CASE LEFT(MonthCol, 3)
            WHEN 'Jan' THEN '01' WHEN 'Feb' THEN '02' WHEN 'Mar' THEN '03' WHEN 'Apr' THEN '04'
            WHEN 'May' THEN '05' WHEN 'Jun' THEN '06' WHEN 'Jul' THEN '07' WHEN 'Aug' THEN '08'
            WHEN 'Sep' THEN '09' WHEN 'Oct' THEN '10' WHEN 'Nov' THEN '11' WHEN 'Dec' THEN '12'
        END) AS YearMonth,
    Allocation
FROM test
UNPIVOT (
    -- 指定要转换的数值列和存储原列名的新列
    Allocation FOR MonthCol IN (Jan20, Feb20, Mar20, Apr20, May20, Jun20, Jul20)
) AS UnpivotResult
ORDER BY StaffID, ProjectID, YearMonth;

方法三:补全年12个月记录(报表完整度要求高)

如果需要确保每个员工-项目组合都有全年12个月的分配记录(即使值为0),可以通过生成年月维度表后关联实现:

-- 生成2020年12个月的日期维度
WITH YearMonths AS (
    SELECT DATEFROMPARTS(2020, month_num, 1) AS YearMonthDate
    FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) AS Months(month_num)
),
-- 获取所有唯一的员工-项目组合
StaffProjects AS (
    SELECT DISTINCT StaffID, ProjectID
    FROM test
)
SELECT
    sp.StaffID,
    sp.ProjectID,
    FORMAT(ym.YearMonthDate, 'yyyy-MM') AS YearMonth,
    -- 用ISNULL将无数据的月份填充为0
    ISNULL(t.Allocation, 0) AS Allocation
FROM StaffProjects sp
CROSS JOIN YearMonths ym
LEFT JOIN (
    -- 先转换原表数据为行格式
    SELECT
        StaffID,
        ProjectID,
        DATEFROMPARTS(
            2000 + CAST(RIGHT(MonthCol, 2) AS INT),
            CASE LEFT(MonthCol, 3)
                WHEN 'Jan' THEN 1 WHEN 'Feb' THEN 2 WHEN 'Mar' THEN 3 WHEN 'Apr' THEN 4
                WHEN 'May' THEN 5 WHEN 'Jun' THEN 6 WHEN 'Jul' THEN 7 WHEN 'Aug' THEN 8
                WHEN 'Sep' THEN 9 WHEN 'Oct' THEN 10 WHEN 'Nov' THEN 11 WHEN 'Dec' THEN 12
            END,
            1
        ) AS YearMonthDate,
        Allocation
    FROM test
    UNPIVOT (
        Allocation FOR MonthCol IN (Jan20, Feb20, Mar20, Apr20, May20, Jun20, Jul20)
    ) AS UnpivotResult
) t ON sp.StaffID = t.StaffID 
    AND sp.ProjectID = t.ProjectID 
    AND ym.YearMonthDate = t.YearMonthDate
ORDER BY sp.StaffID, sp.ProjectID, ym.YearMonthDate;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 00:35:17