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

技术问询:如何从日期列名中仅提取日部分?附月度考勤存储过程代码

解决方案

要从动态生成的日期列名中仅保留日部分,核心是在构建考勤报告的动态列列表时,把完整日期格式化为仅显示日的形式。结合你的存储过程场景,这里是具体的修改方案:

1. 生成仅含日部分的列名列表

首先从你的DATERANGE CTE中提取日期,将其转换为日的字符串形式(比如'01'、'15'),同时用方括号包裹列名避免SQL语法错误。根据你的SQL Server版本,选择对应的拼接方式:

适用于SQL Server 2017及以上(支持STRING_AGG)

DECLARE @Columns NVARCHAR(MAX)
SELECT @Columns = STRING_AGG(QUOTENAME(FORMAT(DT, 'dd')), ', ')
FROM DATERANGE

适用于SQL Server 2016及以下

DECLARE @Columns NVARCHAR(MAX)
SELECT @Columns = STUFF((
    SELECT ', ' + QUOTENAME(FORMAT(DT, 'dd'))
    FROM DATERANGE
    ORDER BY DT
    FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 2, '')

2. 修改动态PIVOT语句

将生成的日列名整合到动态PIVOT逻辑中,替换原来的完整日期列名。以下是整合后的完整存储过程示例(需根据你的实际表结构调整表名和字段):

USE [Attendace]
GO
/****** Object:  StoredProcedure [dbo].[PerDayAttendance]    Script Date: 04/11/2018 20:16:05 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[PerDayAttendance] 
    @STARTDATE DATE, 
    @ENDDATE DATE
AS
BEGIN
    SET NOCOUNT ON;

    WITH DATERANGE AS (
        SELECT DT = DATEADD(DD, 0, @STARTDATE)
        WHERE DATEADD(DD, 1, @STARTDATE) <= @ENDDATE
        UNION ALL
        SELECT DATEADD(DD, 1, DT)
        FROM DATERANGE
        WHERE DATEADD(DD, 1, DT) <= @ENDDATE
    )

    -- 生成仅含日部分的列名
    DECLARE @Columns NVARCHAR(MAX)
    IF EXISTS (SELECT 1 FROM sys.all_objects WHERE name = 'STRING_AGG' AND type = 'FN')
    BEGIN
        SELECT @Columns = STRING_AGG(QUOTENAME(FORMAT(DT, 'dd')), ', ')
        FROM DATERANGE
    END
    ELSE
    BEGIN
        SELECT @Columns = STUFF((
            SELECT ', ' + QUOTENAME(FORMAT(DT, 'dd'))
            FROM DATERANGE
            ORDER BY DT
            FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
    END

    -- 构建动态PIVOT SQL
    DECLARE @DynamicSQL NVARCHAR(MAX)
    SET @DynamicSQL = N'
    SELECT EmployeeID, EmployeeName, ' + @Columns + '
    FROM (
        SELECT 
            emp.EmployeeID,
            emp.EmployeeName,
            ISNULL(att.AttendanceStatus, ''Absent'') AS AttendanceStatus, -- 处理无考勤记录的情况
            FORMAT(d.DT, ''dd'') AS DayOfMonth
        FROM EmployeeMaster emp -- 替换为你的员工表名
        CROSS JOIN DATERANGE d
        LEFT JOIN AttendanceRecords att 
            ON emp.EmployeeID = att.EmployeeID
            AND att.AttendanceDate = d.DT
    ) AS SourceData
    PIVOT (
        MAX(AttendanceStatus)
        FOR DayOfMonth IN (' + @Columns + ')
    ) AS PivotTable
    ORDER BY EmployeeID'

    -- 执行动态SQL并传递参数
    EXEC sp_executesql @DynamicSQL, 
        N'@STARTDATE DATE, @ENDDATE DATE', 
        @STARTDATE = @STARTDATE, 
        @ENDDATE = @ENDDATE
END
GO

关键细节说明

  • 用FORMAT(DT, 'dd')会得到两位数字的日(如01、09),如果想要一位数字格式(如1、9),可以替换为CAST(DAY(DT) AS VARCHAR(2))。
  • QUOTENAME()函数用于包裹列名,避免日为纯数字时触发SQL语法错误(比如列名1需要写成[1])。
  • 示例中用ISNULL处理了员工无考勤记录的情况,你可以根据实际需求调整默认值(比如'未打卡')。

内容的提问来源于stack exchange,提问作者Anushree Sarees Pvt Ltd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 02:28:33