首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >SQL获取“xxxx-xx-xx”之前的第一个可用日期

SQL获取“xxxx-xx-xx”之前的第一个可用日期
EN

Stack Overflow用户
提问于 2016-05-16 15:06:11
回答 6查看 1.2K关注 0票数 0

我需要一个查询,以获得第一个可用日期,向后移动,不包括不可用日期。

示例:

日期必须在2016-05-20之前(此日期是一个变量)。最好的选择是2016-05-19(前一天)。如果这是不可用的,那就提前一天。

不可用日期保存在表中,可以选择如下所示

SELECT blockedDate FROM tbl_BlockedDates

编辑:

我已经看到这样的事情会起作用,但我想不出如何正确地设置它以适应我的情况

代码语言:javascript
运行
复制
 SELECT TOP 1 [Date]
            FROM (
        SELECT TOP (DATEDIFF(DAY, @Date1, @Date2)+1)
        [Date] = dateadd(DAY, ROW_NUMBER() OVER(ORDER BY c1.name), @Date1)
        FROM  [master].[dbo].[spt_values] c1 
            ) D 
            WHERE D.Date NOT IN (SELECT ClosingDate FROM ClosingDays WHERE IsClosedAllDay = 1) 
            and Date not in (SELECT blockedDate FROM tbl_BlockedDates )

我怎么才能得到我需要的日期?

EN

回答 6

Stack Overflow用户

发布于 2016-05-16 15:15:33

为此需要一个日期表。

代码语言:javascript
运行
复制
Declare @start_date datetime = '2014-01-01', 
        @varibale_date datetime = '2016-05-20'

;WITH e1(n) AS
(
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), -- 10
e2(n) AS (SELECT 1 FROM e1 CROSS JOIN e1 AS b), -- 10*10
e3(n) AS (SELECT 1 FROM e1 CROSS JOIN e2), -- 10*100
e4(n) AS (SELECT 1 FROM e3 CROSS JOIN e2), 
Tally(n) AS (select  ROW_NUMBER() OVER (ORDER BY n) FROM e4),
dates(dt) AS (select DATEADD(dd,n-1,@start_date) from tally)
SELECT TOP 1 dt 
FROM   dates 
WHERE  dt < @varibale_date 
       AND NOT EXISTS (SELECT 1 FROM tbl_blockeddates t 
                       WHERE  t.blockeddate = dt) 
ORDER  BY dt DESC 
票数 4
EN

Stack Overflow用户

发布于 2016-05-16 15:20:07

这比听起来要复杂得多,因为你可能会有一连串被封锁的日期,而且必须提前一天。

如果没有阻塞的日期,或者阻塞的日期在所讨论的日期之前有一个空白,这就足够简单了:

代码语言:javascript
运行
复制
with bd as (
      select bd.*, max(grp) as maxgrp
      from (select bd.*,
                   dateadd(day, - row_number() over (order by blockeddate), blockeddate) as grp
            from tbl_BlockedDates bd
            where blockedDate < @Date
           ) bd
     )
select (case when max(blockedDate) is null or
                  max(blockedDate) <> dateadd(day, -1, @Date)
             then dateadd(day, -1, @Date)
             else dateadd(day, -1, min(case when grp = maxgrp then blockedDate end))
        end) as FreeDate
from bd;

else部分是棘手的部分。grp定义了一组连续日期。min()正在获取这样一个组的第一个日期,并在当天减去。

票数 2
EN

Stack Overflow用户

发布于 2016-05-16 15:31:01

代码语言:javascript
运行
复制
DECLARE @DateVariable DATE = '20160520';

SELECT  TOP (1) 
        YT.yourDate 
FROM    yourTable AS [YT] 
WHERE   YT.yourDate < @DateVariable
AND NOT EXISTS (SELECT 1 FROM tbl_BlockedDate AS [bd] WHERE bd.blockedDate = YT.yourDate)
ORDER BY 
    YT.yourDate DESC;

这里的一个问题是,您还没有为您的日历表提供DDL语句(如果您没有DDL语句,则Zohar and在您的问题评论中对此提出了一个很好的观点和解决方案)。

但是,如果您确实有一个日历表或一个包含日期的表,那么您可能需要小心其中的多个条目,其中有一个日期与您的tbl_BlockedDate表中不存在的日期相同。

示例

代码语言:javascript
运行
复制
ID  |  Date         |
---------------------
1   | '2016-05-20'  |
2   | '2016-05-19'  |
3   | '2016-05-19'  |
4   | '2016-05-19'  |
5   | '2016-05-19'  |

上面的查询将返回1行,日期为19,但多行满足查询。

如果您将查询更改为包含WITH TIES,它将返回所有4条记录和19条记录,因为它们都满足此查询。

代码语言:javascript
运行
复制
SELECT  TOP (1) WITH TIES
        YT.yourDate 
FROM    yourTable AS [YT] 
WHERE   YT.yourDate < @DateVariable
AND NOT EXISTS (SELECT 1 FROM tbl_BlockedDate AS [bd] WHERE bd.blockedDate = YT.yourDate)
ORDER BY 
    YT.yourDate DESC;

这就是为什么我们建议在您的订单中包括另一个标识列,希望能够消除这个问题。

下面的示例使用合成列ID返回带有Date: '2016-05-19'ID: 2的行。

代码语言:javascript
运行
复制
SELECT  TOP (1) 
            YT.yourDate 
    FROM    yourTable AS [YT] 
    WHERE   YT.yourDate < @DateVariable
    AND NOT EXISTS (SELECT 1 FROM tbl_BlockedDate AS [bd] WHERE bd.blockedDate = YT.yourDate)
    ORDER BY 
        YT.yourDate DESC,
        YT.identifying_column ASC;
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37257153

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档