SQLite在一个范围内选择日期,但不包括星期日和一些节假日

时间:2018-06-19 18:30:26

标签: sqlite date weekday

以下代码

WITH RECURSIVE dates(x) AS ( 
            SELECT '2017-11-01'
                UNION ALL 
            SELECT DATE(x, '+1 DAYS') FROM dates WHERE x<'2018-01-31' AND 'weekday'>0
        ) 
        SELECT * FROM dates;

不从日期中排除星期日。为什么不呢?

我还想从日期的结果集中排除某些日期,这些日期位于数据库的另一个表中。我们称该表为假期。该表的架构可能是这样的:

CREATE TABLE Holidays (
    id              INTEGER PRIMARY KEY
                            UNIQUE,
    NameOfHoliday      TEXT    DEFAULT NULL,
    startDate DATE    DEFAULT NULL,
    endDate DATE    DEFAULT NULL
);

让一些数据插入“假期”表:

INSERT INTO Holidays VALUES(1,'Winter Break','2017-12-23','2018-01-14');

然后如何在上述“假期”表中使用上述CTE来获得包含日期但不包含星期日,并且在假期中不包含开始日期和结束日期之间的日期的结果?

最好,朋友

1 个答案:

答案 0 :(得分:1)

问题的一部分是,“工作日”(字符串)将始终大于0,因此测试将始终为真。

第二个问题是,当右(递归)SELECT返回空结果时,递归停止。因此,如果您在此选择中对星期日进行了测试,那么在不满足条件时将不再进行递归。因此,只会选择直到第一个星期日(星期日将导致没有行)之前的数据(因为2017-09-01是星期五,您将仅获得2行,而第3个是星期日)。因此,周日的测试应该在递归之后进行。

您想要的是将星期几作为0-6的整数(Sun-Sat)。您可以使用strftime('%w',valid_date)来获取值,但随后需要确保它是整数而不是text / char / string,以便可以使用CAST(strftime('%w',valid_date) As INTEGER)

要修复直到第一个星期日为止的行,用于删除星期日的WHERE子句应位于递归后的最终SELECT中。

因此,以下是针对您可能会使用的问题的修复程序:-

WITH RECURSIVE dates(x) AS ( 
            SELECT '2017-09-01'
                UNION ALL 
            SELECT DATE(x, '+1 DAYS') FROM dates WHERE x <'2017-09-30'
        ) 
        SELECT x FROM dates WHERE CAST(strftime('%w',x) As INTEGER) > 0;

这将导致26行,而不是30行。 :-

enter image description here

......

  • 即排在第三和第十(依此类推)。

其他

是其他问题:-

  

我也想从日期结果集中排除一些日期   哪些日期在数据库的另一个表中。让我们称之为   表假期。该表的架构可能是这样的:

CREATE TABLE Holidays (
    id              INTEGER PRIMARY KEY
                            UNIQUE,
    NameOfHoliday      TEXT    DEFAULT NULL,
    startDate DATE    DEFAULT NULL,
    endDate DATE    DEFAULT NULL
);
     

让一些数据插入“假期”表:

INSERT INTO Holidays VALUES(1,'Winter Break','2017-12-23','2018-01-14');

这非常复杂,尤其是因为您可能要考虑多个假期(例如,您想整整一年)。我建议的是,要有一个包含各个假期日期的表,而不是在两列中包含一个日期范围,那么这很容易满足。

可以说有一个更简单的AltHolidays表,而不是Holidays表。 :-

CREATE TABLE IF NOT EXISTS AltHolidays (NameOfHoliday TEXT, Day_To_Exclude TEXT);
INSERT OR IGNORE INTO AltHolidays VALUES
    ('Winter Break','2017-12-23'),
    ('Winter Break','2017-12-24'),
    ('Winter Break','2017-12-25'),
    ('Winter Break','2017-12-26'),
    ('Winter Break','2017-12-27'),
    ('Winter Break','2017-12-28'),
    ('Winter Break','2017-12-29'),
    ('Winter Break','2017-12-30'),
    ('Winter Break','2017-12-31'),
    ('Winter Break','2018-01-01'),
    ('Winter Break','2018-01-02'),
    ('Winter Break','2018-01-03'),
    ('Winter Break','2018-01-04'),
    ('Winter Break','2018-01-05'),
    ('Winter Break','2018-01-06'),
    ('Winter Break','2018-01-07'),
    ('Winter Break','2018-01-08'),
    ('Winter Break','2018-01-09'),
    ('Winter Break','2018-01-10'),
    ('Winter Break','2018-01-11'),
    ('Winter Break','2018-01-12'),
    ('Winter Break','2018-01-13'),
    ('Winter Break','2018-01-14')
;
  • 理想情况下,描述将保存在其自己的表中并被引用。

然后(假设您仍然希望也排除星期日),您可以使用NOT IN,例如:-

WITH RECURSIVE dates(x) AS ( 
            SELECT '2017-11-01'
                UNION ALL 
            SELECT DATE(x, '+1 DAYS') FROM dates WHERE x<'2018-01-31'
        ) 
        SELECT * 
                FROM dates 
                WHERE x NOT IN (SELECT Day_To_Exclude FROM AltHolidays) -- Exclude holidays
                    AND CAST(strftime('%w',x) AS INTEGER) <> 0 -- Exclude Sundays
;

这将导致60行(92-23(节假日)-9(其余星期日))