Select Firebird 中给定范围内的日期列表
Select list of dates from given range in Firebird
我正在设计 returns 下周到期的 PurchaseOrder 的报表。
我在 returns PurchaseOrder
下面添加的查询由于特定的 Commodity
、AmountDue
及其 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
忽略你对数据类型的奇怪使用*,有几种可能的解决方案:
- 使用包含日期的 'calendar' table,然后右连接到 table(或从 table 左连接)。缺点当然是必须填充此 table(但这是一次性成本)。
- 使用选择table 存储过程生成日期范围并加入该范围。
- 在查询本身的递归通用 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'
将日期转换为该数值。
我正在设计 returns 下周到期的 PurchaseOrder 的报表。
我在 returns PurchaseOrder
下面添加的查询由于特定的 Commodity
、AmountDue
及其 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
忽略你对数据类型的奇怪使用*,有几种可能的解决方案:
- 使用包含日期的 'calendar' table,然后右连接到 table(或从 table 左连接)。缺点当然是必须填充此 table(但这是一次性成本)。
- 使用选择table 存储过程生成日期范围并加入该范围。
- 在查询本身的递归通用 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'
将日期转换为该数值。