如何在TVF或SP中使用CTE?

时间:2016-11-09 13:43:25

标签: sql-server

这是我的出勤表。

CREATE TABLE [dbo].[StaffAttendance](
    [StaffId] [int] NOT NULL,
    [Date] [date] NOT NULL CONSTRAINT [DF__StaffAtten__Date__6CA31EA0]  DEFAULT (getdate()),
    [AttendanceStatusId] [int] NOT NULL,
    [AttendanceId] [int] IDENTITY(1,1) NOT NULL,
 CONSTRAINT [PK__StaffAtt__8B69261DC5CF4AF2] PRIMARY KEY NONCLUSTERED 
(
    [AttendanceId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
 CONSTRAINT [UNIQ_staffDates] UNIQUE CLUSTERED 
(
    [StaffId] ASC,
    [Date] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[StaffAttendance]  WITH CHECK ADD  CONSTRAINT [FK__StaffAtte__Atten__6E8B6712] FOREIGN KEY([AttendanceStatusId])
REFERENCES [dbo].[AttendanceStatus] ([AttendanceStatusId])
GO

ALTER TABLE [dbo].[StaffAttendance] CHECK CONSTRAINT [FK__StaffAtte__Atten__6E8B6712]
GO

ALTER TABLE [dbo].[StaffAttendance]  WITH CHECK ADD  CONSTRAINT [FK__StaffAtte__Staff__6D9742D9] FOREIGN KEY([StaffId])
REFERENCES [dbo].[Staff] ([StaffId])
GO

ALTER TABLE [dbo].[StaffAttendance] CHECK CONSTRAINT [FK__StaffAtte__Staff__6D9742D9]
GO

这个查询

SELECT [StaffId],
       [Date],
       [AttendanceStatusId]
  FROM [idiot].[dbo].[StaffAttendance]

给我这个结果。简单的每日考勤记录。

Simple attendance recording

出于报告目的,我创建了此SP。

CREATE PROCEDURE [dbo].[spGetAllStaffCollectiveAttendanceByMonth]
@StartDate DATE,
@EndDate DATE
AS
BEGIN
SELECT
        StaffAttendance.StaffId,
        DATENAME(MONTH, @StartDate) AS [ForMonth],
        (DATEDIFF(dd, @StartDate, @EndDate) + 1)-(DATEDIFF(wk, @StartDate, @EndDate) * 1)-(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END) AS TotalWorkingDays,
        SUM(StaffAttendance.AttendanceStatusId) AS TotalDaysWorked
        FROM StaffAttendance 
        WHERE [Date] BETWEEN @StartDate AND @EndDate AND StaffAttendance.AttendanceStatusId = 1 GROUP BY StaffAttendance.StaffId
END
GO

忽略所有星期日,并在2个日期之间获得总出勤率。如果我执行它,

EXEC [dbo].[spGetAllStaffCollectiveAttendanceByMonth]
  @StartDate = '2016-10-01', @EndDate = '2016-10-31'

这就是它所设想的

SP result

现在我想要做的只是将varchar类型作为月份名称而不是日期类型进行输入。喜欢'十月'而不是[@StartDate =' 2016-10-01',@ EndDate =' 2016-10-31']所以它自己获得开始和结束日期并给我报告输出(第2张图片)

我获得了一个月一个月的开始和结束日期的帮助。这就是它的完成方式。

DECLARE @month VARCHAR(9) = 'october';

WITH CteMonths(n, m) AS(
    SELECT 1, 'January' UNION ALL
    SELECT 2, 'February' UNION ALL
    SELECT 3, 'March' UNION ALL
    SELECT 4, 'April' UNION ALL
    SELECT 5, 'May' UNION ALL
    SELECT 6, 'June' UNION ALL
    SELECT 7, 'July' UNION ALL
    SELECT 8, 'August' UNION ALL
    SELECT 9, 'September' UNION ALL
    SELECT 10, 'October' UNION ALL
    SELECT 11, 'November' UNION ALL
    SELECT 12, 'December'
)
SELECT
    DATEADD(MONTH, n - 1, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)) AS StartDate,
    DATEADD(DAY, -1, DATEADD(MONTH, n, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0))) AS EndDate
FROM CteMonths
WHERE m = @month

它确实让我得到了这个

enter image description here

但是我不知道如何在我的SP中嵌入这个CTE,这样我所要做的就是输入月份名称 - 没有日期,没有月份号码 - 只是月份名称,我的SP会返回相同的结果。我现在已经尝试过3到4个小时了,但这对我来说很重要而且我失去了焦点。任何/所有帮助将受到高度赞赏。

1 个答案:

答案 0 :(得分:1)

您可以按照以下步骤将CTE放入程序中。如果您没有将;放在CTE前面,您将收到此消息。

  

关键字'附近有'的语法不正确。如果此语句是公用表表达式,xmlnamespaces子句或更改跟踪上下文子句,则必须以分号结束前一个语句。

CREATE PROCEDURE [dbo].[spGetAllStaffCollectiveAttendanceByMonth]
@Month nvarchar(255)
AS
BEGIN

Declare @StartDate DATE,
@EndDate DATE

;WITH CteMonths(n, m) AS(
    SELECT 1, 'January' UNION ALL
    SELECT 2, 'February' UNION ALL
    SELECT 3, 'March' UNION ALL
    SELECT 4, 'April' UNION ALL
    SELECT 5, 'May' UNION ALL
    SELECT 6, 'June' UNION ALL
    SELECT 7, 'July' UNION ALL
    SELECT 8, 'August' UNION ALL
    SELECT 9, 'September' UNION ALL
    SELECT 10, 'October' UNION ALL
    SELECT 11, 'November' UNION ALL
    SELECT 12, 'December'
  )
SELECT @StartDate = DATEADD(MONTH, n - 1, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)), 
@EndDate = DATEADD(DAY, -1, DATEADD(MONTH, n, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)))
FROM CteMonths
WHERE m = @month

SELECT
    StaffAttendance.StaffId,
    DATENAME(MONTH, @StartDate) AS [ForMonth],
    (DATEDIFF(dd, @StartDate, @EndDate) + 1)-(DATEDIFF(wk, @StartDate, @EndDate) * 1)-(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END) AS TotalWorkingDays,
    SUM(StaffAttendance.AttendanceStatusId) AS TotalDaysWorked
    FROM StaffAttendance 
    WHERE [Date] BETWEEN @StartDate AND @EndDate AND StaffAttendance.AttendanceStatusId = 1 GROUP BY StaffAttendance.StaffId
END
GO