【问题标题】:Find start date based upon End Date and Duration - T-SQL根据结束日期和持续时间查找开始日期 - T-SQL
【发布时间】:2013-09-22 13:32:27
【问题描述】:

我在 SQL Server 中有一个表,它具有以下属性。

ProjectID ||  Start_Date  ||   End Date    || Duration(Days)
1                             10-Jan-2013      5
2                             02-FEB 2013      16   
3                             26-Mar-2013      50  
.                                 .             .

我想根据符合条件的日期(周一至周五)查找开始日期。例如结束日期:1 月 10 日开始日期将是 1 月 4 日,因为 1 月 5 日和 6 日是星期六和星期日。

我想知道这在 T-SQL(函数、自定义 T-SQL 块)中是如何实现的。非常感谢任何指导和帮助。

【问题讨论】:

  • 为什么 1 月 4 日没有资格?现在是星期五,根据你的清单,它应该可以工作。根据您的输入和预期输出,您似乎希望结束日期减去 5 个工作日,其中工作日是周一至周五的任何一天。请说明您想要两者中的哪一个。
  • @Neolisk 1 月 4 日将获得资格。对此感到抱歉。如果持续时间大于 5 天,我如何才能找到开始日期。

标签: sql-server tsql date


【解决方案1】:

应该这样做:

WITH tblProjects2 AS (
SELECT ProjectId, DATEADD(DAY, -Duration, EndDate) AS StartDate FROM tblProjects
)
SELECT ProjectId,
  CASE WHEN DATENAME(DW, StartDate) = 'Sunday' THEN DATEADD(day, -2, StartDate)
       WHEN DATENAME(DW, StartDate) = 'Saturday' THEN DATEADD(day, -1, StartDate)
       ELSE StartDate END AS ProperStartDate
  FROM tblProjects2

方法相当简单 - 如果您的新日期是周末,则分别减去 1 天或 2 天,具体取决于是周六还是周日。

tblProjects 的测试用例结构:

CREATE TABLE [dbo].[tblProjects](
  [ProjectId] [int] NULL,
  [StartDate] [date] NULL,
  [EndDate] [date] NULL,
  [Duration] [int] NULL
)

相同的测试用例数据:

INSERT INTO tblProjects VALUES (1, NULL, '10-Jan-2013', 5);
INSERT INTO tblProjects VALUES (2, NULL, '02-FEB-2013', 16);
INSERT INTO tblProjects VALUES (3, NULL, '26-Mar-2013', 50);

EDIT - 相同的功能,使用一个函数:

CREATE FUNCTION dbo.getStartDate(@EndDate Date, @Duration int)
RETURNS DATE
AS
BEGIN
   DECLARE @newDate DATE;
   SET @newDate = DATEADD(day, -@Duration, @EndDate);

   RETURN (CASE 
         WHEN DATENAME(DW, @newDate) = 'Sunday' THEN DATEADD(day, -2, @newDate)
         WHEN DATENAME(DW, @newDate) = 'Saturday' THEN DATEADD(day, -1, @newDate)
         ELSE @newDate END)
END;

然后你可以像这样重写上面的查询:

SELECT ProjectId, dbo.getStartDate(EndDate, Duration) AS StartDate
  FROM tblProjects

【讨论】:

  • 非常感谢,它运行良好。你能把它写成一个 T-SQL 函数,这样我就可以输入 End_Date 和 Working Day 并得到 StartDate 作为输出。
  • @wali:不客气。请提供您想要的 T-SQL 函数的示例用法。我不太清楚你打算如何指定工作日。还有持续时间呢?如果我是你,我会将周日和周六的处理部分包装到一个函数中,而将其他所有内容排除在外。因此,输入将是 DATE 类型的单个参数,输出是 DATE 根据需要向后移动 1-2 天以表示工作日。然后,您可以在上面的示例中使用一个 SELECT。
  • 我使用以下查询来更新我的表。 WITH tblProjects2 AS ( SELECT ProjectId, DATEADD(DAY, -Duration, EndDate) AS StartDate FROM tblProjects ) Update orig_project_table set start_date = (select CASE WHEN DATENAME(DW, StartDate) = 'Sunday' THEN DATEADD(day, -2, StartDate) WHEN DATENAME(DW, StartDate) = 'Saturday' THEN DATEADD(day, -1, StartDate) ELSE StartDate END AS ProperStartDate FROM tblProjects2 where tblProjects2.ProjectID = orig_project_table.ProjectID);
  • 如果可以,请编写一个执行上述查询功能并具有以下签名的函数。 Return Date getStartDate(@EndDate Date, @Duration int){}
  • 再次感谢。 @Neolisk。
【解决方案2】:

阅读难度稍大,但速度稍快

SELECT ProjectId, 
DATEADD(d, -Duration - CASE DATEDIFF(d, +Duration, EndDate) % 7 
  WHEN 5 THEN 1 
  WHEN 6 THEN 2 
  ELSE 0 END
  , EndDate)
FROM tblProjects

【讨论】: