SQLite 到 select 日期在一个范围内但没有星期日和一些节假日

SQLite to select dates within a range but without Sundays and some holidays

以下代码

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;

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

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

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

让我们在假期中插入一些数据 table:

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

那么如何将上述 CTE 与此假期一起使用 table 来获得包含日期但没有星期日且假期中的开始日期和结束日期之间没有日期的结果?

最好的,伙计

您的部分问题是 'weekday'(字符串)将始终大于 0,因此测试将始终为真。

第二个问题是当从右边(递归)返回空结果时递归停止SELECT。因此,如果您在此 select 中进行了星期日的测试,那么当条件不满足时将不再进行递归。因此,只有第一个星期日(星期日将导致没有行)之前的数据会被 selected(因为 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 行,例如:-

......

  • 即第 3 个和第 10 个被排除(依此类推)。

额外

关于附加问题:-

Also I would like to exclude some dates from the result set of dates which dates are in another table in the database. Let is call that table Holidays. The schema for that table could be like this:

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

Let insert some data into Holidays table:

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

这非常复杂,尤其是因为您可能需要考虑多个假期(假设您想要整整一年)。我的建议是,不要在两列中设置日期范围,而是使用 table 和单独的假期日期,这样就很容易满足。

而不是假期 table 让我们说有更简单的 AltHolidays table 例如:-

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')
;
  • 理想情况下,描述会保存在它自己的 table 中,并且会被引用。

然后(假设您还想排除星期日)您可以使用 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(其余星期日))