Select Firebird 中给定范围内的日期列表

Select list of dates from given range in Firebird

我正在设计 returns 下周到期的 PurchaseOrder 的报表。

我在 returns PurchaseOrder 下面添加的查询由于特定的 CommodityAmountDue 及其 DeliveryDate.

显然只有 returns PO_Dates 在 table 中。我想要的是还包括预期没有 PO 的日期,即那些单元格为 null。

对我来说,一种可能性是在 Date 列上使用未来一周的一组日期 LEFT JOIN 数据集,这最终会使结果为空,而无需采购订单。

在 Firebird 中,我不知道如何 select 一周长日期列表,然后在连接中使用它。

SELECT
    PURCHASE_ORDER_DET.COMMODITYID AS COM_ID,
    PURCHASE_ORDER_DET.DELIVERYDATE + CAST ('29.12.1899' AS DATE) as DLV_DATE,
    SUM(PURCHASE_ORDER_DET.REQQUANTITY) as DLV_DUE
FROM
    PURCHASE_ORDER_DET
LEFT JOIN PURCHASE_ORDER_HDR on PURCHASE_ORDER_HDR.POH_ID = 
PURCHASE_ORDER_DET.POH_ID
WHERE 
    PURCHASE_ORDER_DET.COMMODITYID = 1
    AND PURCHASE_ORDER_HDR.STATUS in (0,1,2)
    AND PURCHASE_ORDER_DET.DELIVERYDATE + CAST ('30.12.1899' AS TIMESTAMP) >= '3.01.2019'
    AND PURCHASE_ORDER_DET.DELIVERYDATE + CAST ('30.12.1899' AS TIMESTAMP) <= '9.01.2019'
    AND PURCHASE_ORDER_DET.DELETED is NULL
Group by 
    PURCHASE_ORDER_DET.COMMODITYID,
    PURCHASE_ORDER_DET.DELIVERYDATE

数据集

COM_ID    DLV_DATE       DLV_DUE    
1         3.01.2019     50.000000
1         5.01.2019     10.000000

预计

COM_ID    DLV_DATE       DLV_DUE    
1         3.01.2019     50.000000
1         4.01.2019     null
1         5.01.2019     10.000000
1         6.01.2019     null
1         7.01.2019     null
1         8.01.2019     null
1         9.01.2019     null

忽略你对数据类型的奇怪使用*,有几种可能的解决方案:

  1. 使用包含日期的 'calendar' table,然后右连接到 table(或从 table 左连接)。缺点当然是必须填充此 table(但这是一次性成本)。
  2. 使用选择table 存储过程生成日期范围并加入该范围。
  3. 在查询本身的递归通用 table 表达式中生成范围

选项 1 不言自明。

选项 2 类似于:

CREATE OR ALTER PROCEDURE date_range(startdate date, enddate date)
  RETURNS (dateval date)
AS
BEGIN
    dateval = startdate;
    while (dateval <= enddate) do
    BEGIN
       suspend;
       dateval = dateval + 1;
    END
END

然后在您的查询中使用它,例如:

select date_range.dateval, ...
from date_range(date'2019-01-03', date'2019-01-09') -- use date_range(?, ?) for parameters
left join ...
  on date_range.dateval = ...

选项 3 类似于:

WITH RECURSIVE date_range AS (
    SELECT date'2019-01-03' dateval  -- start date, use cast(? as date) if you need a parameter
    FROM rdb$database
    UNION ALL 
    SELECT dateval + 1
    FROM date_range
    WHERE dateval < date'2019-01-09' -- end date use ? if you need a parameter
)
SELECT *
FROM date_range
LEFT JOIN ... 
  ON date_range.dateval = ... 

递归通用 table 表达式的最大递归深度为 1024,这意味着如果您需要超过 1024 天的跨度,则它不是 suitable。


*:我建议您开始使用 DATE 而不是自 30-12-1899 以来的天数。这样就避免了像现在这样进行笨拙的计算。如果您确实需要这些天数,那么您可以使用 datediff(DAY FROM date'1899-12-30' TO somedatevalue)somedatevalue - date'1899-12-30' 将日期转换为该数值。