如何提取 table 中只有开始和结束日期值的日期范围之间的数据?

How to extract data between a date range which has only start and end date values in the table?

我有一个table,有10+万条记录,结构如下-

Store ID Item ID item_active_Date item_inactive_date
NY0001 FMC0001 2021-10-30 2021-11-30
NY0001 FMC0002 2021-01-10 2021-06-14
NY0002 FMC0003 2021-09-01 2021-09-10
NY0002 FMC0004 2021-01-01 2021-03-31
NY0003 FMC0005 2021-04-01 2021-05-30
NY0003 FMC0006 2021-06-02 2021-06-24
NY0004 FMC0007 2021-01-02 Null

需要确定 item_ID 在给定日期范围内可用。只有 item_active 和 item_inactive 日期可用。

考虑在“2021-06-15”和“2021-11-25”之间可用的 item_ID。预期结果如下(当item_inactive日期不可用时视为今天)-

Store ID Item ID item_active_Date item_inactive_date
NY0001 FMC0001 2021-10-30 2021-11-30
NY0002 FMC0003 2021-09-01 2021-09-10
NY0003 FMC0006 2021-06-02 2021-06-24
NY0004 FMC0007 2021-01-02 Null

我相信按照这些思路应该可行:

SELECT item_ID FROM my_table
    WHERE item_active_date <= $endDate
        AND (item_inactive_date IS NULL
            OR item_inactive_date > $startDate);

虽然您需要确保您的 SQL 引擎将这些不等式中的值解释为日期,而不是字符串,因为您的 table 使用的格式在月和月之间有天数年.

你可以这样做:

SELECT * FROM Sample
WHERE 
  item_active_Date BETWEEN  '2021-06-15' and '2021-11-25' 
 OR item_inactive_date BETWEEN  '2021-06-15' and '2021-11-25' 
 OR item_active_Date IS NULL 

Fiddle

根据评论更新

Consider the scenario where for an item_id active_date = '2021-06-01' and inactive_date = '2021-11-29'. This should also be part of the result as the item was 'ACTIVE' between our query date range

如果我正确理解了您的要求,将很难获得未在日期范围内记录(或跟踪)的结果(除非有其他标志或列可以处理)。例如,如果项目在给定开始日期前一天处于活动状态,并在结束日期后标记为不活动,则它不会显示在结果中,因为没有每天监控项目的记录 activity.同样,没有无效日期的项目(假设它们仍然有效)也会有同样的问题。

因此,为了获得准确的结果并使查询更容易,您需要根据活动和非活动日期重新生成项目活动。所以,我们需要先填补日期空白。以项目 FMC0003 为例,它在 2021-09-01 上处于活动状态,在 '2021-09-10' 上处于非活动状态。我们将需要重新生成它以记录从活动日期到非活动日期的每个日期。因此,在我们的示例中,项目 FMC0003 将有 10 条记录。这将应用于 table.

中的所有记录

示例:

;WITH CTE AS (
    SELECT 
        [Store ID],
        [Item ID], 
        item_active_Date ,
        ISNULL(item_inactive_date, GETDATE()) item_inactive_date
    FROM Sample s
    UNION ALL
    SELECT 
        c.[Store ID],
        c.[Item ID], 
        DATEADD(DAY, 1, c.item_active_Date) ,
        c.item_inactive_date
    FROM CTE c
    WHERE 
        DATEADD(DAY, 1, c.item_active_Date) <= c.item_inactive_date 
)
SELECT *
FROM Sample
WHERE EXISTS
(
    SELECT * FROM CTE c 
    WHERE c.item_active_Date BETWEEN '2021-06-15' AND '2021-11-25'  
)
ORDER BY [Store ID], [Item ID], item_active_Date
OPTION (MAXRECURSION 0)

找到重叠区间的正确方法是比较一个人的开始和另一个人的结束,另一个人的开始和第一个人的结束。

这比使用复杂的 OR 条件要高效得多,因为您正在执行直线范围查找。您的设置确实有一个缺点,即 item_inactive_date 可以为空,因此您需要在 item_active_Date 上建立索引。

SELECT *
FROM YourTable t
WHERE t.item_active_Date < '2021-11-25'
  AND (t.item_inactive_date IS NULL OR t.item_inactive_date > '2021-06-15');

db<>fiddle

您可能需要根据您想要的逻辑将 < 调整为 <=