我正在做一个小型旅馆预订项目。我尝试在网格上创建日历列表,该列表显示一个月的所有日期,并且日期旁边是旅馆的交易明细(预订明细或预订明细)。
这是我的示例数据:
交易表
SALE_PK SALESPARTICULAR SALES_DATEFROM SALES_DATETO
------------------------------------------------------------
1 Room 1-Reserved 5/17/2019 5/18/2019
2 Room 2-Reserved 5/18/2019 5/20/2019
3 Room 3-Reserved 5/22/2019 5/23/2019
这是我想要的输出:
选择过程
GET_DATE SALES_DSCRPTION
--------------------------
5/1/2019 Null
5/2/2019 Null
5/3/2019 Null
5/4/2019 Null
5/5/2019 Null
5/6/2019 Null
5/7/2019 Null
5/8/2019 Null
5/9/2019 Null
5/10/2019 Null
5/11/2019 Null
5/12/2019 Null
5/13/2019 Null
5/14/2019 Null
5/15/2019 Null
5/16/2019 Null
5/17/2019 Room 1-Reserved 5/17/2019-5/18/2019
5/18/2019 Room 1-Reserved 5/17/2019-5/18/2019
5/18/2019 Room 2-Reserved 5/18/2019-5/20/2019
5/19/2019 Room 2-Reserved 5/18/2019-5/20/2019
5/20/2019 Room 2-Reserved 5/18/2019-5/20/2019
5/21/2019 Null
5/22/2019 Room 3-Reserved 5/22/2019-5/23/2019
5/23/2019 Room 3-Reserved 5/22/2019-5/23/2019
5/24/2019 Null
5/25/2019 Null
5/26/2019 Null
5/27/2019 Null
5/28/2019 Null
5/29/2019 Null
5/30/2019 Null
5/31/2019 Null
我的选择过程只能在一个日期上获取一个数据。
这是我程序的实际输出
GET_DATE SALES_DSCRPTION
---------------------------
5/14/2019 Null
5/15/2019 Null
5/16/2019 Null
5/17/2019 Room 1-Reserved 5/17/2019-5/18/2019
5/18/2019 Room 1-Reserved 5/17/2019-5/18/2019
5/19/2019 Room 2-Reserved 5/18/2019-5/20/2019
5/20/2019 Room 2-Reserved 5/18/2019-5/20/2019
5/21/2019 Null
5/22/2019 Room 3-Reserved 5/22/2019-5/23/2019
5/23/2019 Room 3-Reserved 5/22/2019-5/23/2019
5/24/2019 Null
5/25/2019 Null
...
我希望在一个日期中显示多个交易。
我创建了一个过程,该过程将显示该月的所有日期。
CREATE PROCEDURE DAYS_IN_MONTH(
Y INTEGER,
M INTEGER)
RETURNS(
D DATE)
AS
begin
d = cast(y || '-' || m || '-01' as date);
while (extract(month from d) = m) do
begin
suspend;
d = d + 1;
end
end;
并将此过程称为我的主选择过程。
这是我正在处理的选择过程。
CREATE PROCEDURE SALES_LISTCALENDAR(
Y INTEGER,
M INTEGER)
RETURNS(
MONTHDATE DATE,
DAYINWORDS VARCHAR(20) CHARACTER SET ISO8859_1 COLLATE ISO8859_1,
SALES_DSCRPTION VARCHAR(200) CHARACTER SET ISO8859_1 COLLATE ISO8859_1)
AS
DECLARE VARIABLE COMPLETE_DATE DATE;
BEGIN
FOR
SELECT
DAYS_IN_MONTH.D,
1 + DAYS_IN_MONTH.D,
CASE extract (WEEKDAY from DAYS_IN_MONTH.D)
WHEN '0' THEN 'Sunday'
WHEN '1' THEN 'Monday'
WHEN '2' THEN 'Tuesday'
WHEN '3' THEN 'Wednesday'
WHEN '4' THEN 'Thursday'
WHEN '5' THEN 'Friday'
WHEN '6' THEN 'Saturday'
ELSE '' END,
A.SALESPARTICULAR
FROM DAYS_IN_MONTH (:Y, :M)
LEFT JOIN
(SELECT A.SALE_PARTICULARS AS SALESPARTICULAR
FROM SALES A WHERE :COMPLETE_DATE >= A.SALES_DATEFROM AND :COMPLETE_DATE <= A.SALES_DATETO
GROUP BY A.SALE_PARTICULARS ) A ON DAYS_IN_MONTH.D = :COMPLETE_DATE
INTO
:MONTHDATE,
:COMPLETE_DATE,
:DAYINWORDS,
:SALES_DSCRPTION
DO
BEGIN
SUSPEND;
END
END;
实际结果
GET_DATE SALES_DSCRPTION
...
5/14/2019 Null
5/15/2019 Null
5/16/2019 Null
5/17/2019 Room 1-Reserved 5/17/2019-5/18/2019
5/18/2019 Room 1-Reserved 5/17/2019-5/18/2019
5/19/2019 Room 2-Reserved 5/18/2019-5/20/2019
5/20/2019 Room 2-Reserved 5/18/2019-5/20/2019
5/21/2019 Null
5/22/2019 Room 3-Reserved 5/22/2019-5/23/2019
5/23/2019 Room 3-Reserved 5/22/2019-5/23/2019
5/24/2019 Null
5/25/2019 Null
...
我的选择过程只能在一个日期上获取一个数据。
这是所需的输出
GET_DATE SALES_DSCRPTION
...
5/14/2019 Null
5/15/2019 Null
5/16/2019 Null
5/17/2019 Room 1-Reserved 5/17/2019-5/18/2019
5/18/2019 Room 1-Reserved 5/17/2019-5/18/2019
5/18/2019 Room 2-Reserved 5/18/2019-5/20/2019
5/19/2019 Room 2-Reserved 5/18/2019-5/20/2019
5/20/2019 Room 2-Reserved 5/18/2019-5/20/2019
5/21/2019 Null
5/22/2019 Room 3-Reserved 5/22/2019-5/23/2019
5/23/2019 Room 3-Reserved 5/22/2019-5/23/2019
5/24/2019 Null
5/25/2019 Null
...
答案 0 :(得分:2)
即使在选择开始时是:COMPLETE_DATE
,您在选择中使用NULL
还是很可疑。我什至都不知道Firebird会在中间执行时填充并应用该变量,就好像它是一个别名一样。另外,该子选择本身看起来很奇怪,我不确定您要使用它做什么。
通过一些测试(在5月1日添加带有SALES_DATEFROM
的记录),看来这是由于评估顺序所致:在该子集的WHERE
子句中,选择:COMPLETE_DATE
变量仍具有上一行的值(这可能是您将其定义为1 + DAYS_IN_MONTH.D
的原因)。由于5月1日是第一行,因此:COMPLETE_DATE
仍为NULL
。但是,在5月18日,您有两个记录(用于1号和2号房间),但是当评估2号房间的记录时,联接条件不再适用,因为:COMPLETE_DATE
的值在用于2号房间的记录时已更新。输出了房间1。
长话短说:请勿在同一查询中使用查询的输出变量。考虑到评估顺序的副作用,应该将其行为定义为不确定。
替换
FROM DAYS_IN_MONTH (:Y, :M)
LEFT JOIN
(SELECT A.SALE_PARTICULARS AS SALESPARTICULAR
FROM SALES A WHERE :COMPLETE_DATE >= A.SALES_DATEFROM AND :COMPLETE_DATE <= A.SALES_DATETO
GROUP BY A.SALE_PARTICULARS ) A ON DAYS_IN_MONTH.D = :COMPLETE_DATE
使用
FROM DAYS_IN_MONTH (:Y, :M)
LEFT JOIN
SALES A on DAYS_IN_MONTH.D BETWEEN A.SALES_DATEFROM AND A.SALES_DATETO
可以解决问题,而且-我认为-也更易于理解。
答案 1 :(得分:2)
不需要这么复杂的代码即可完成如此简单的任务:它只会使您感到困惑。
似乎您只需要一个基于原始循环的原始存储过程,即可生成时间跨度(最左列)中的所有日期,然后只需用预订表对那个SP进行LEFT JOIN
。
Select D, SALESPARTICULAR || ' ' || SALES_DATEFROM || ' - ' || SALES_DATETO
From DAYS_IN_MONTH(...)
LEFT JOIN Transactions
ON D BETWEEN SALES_DATEFROM AND SALES_DATETO