使用left join显示日历列表select过程,并在一个日期显示多个数据
Display a calendar list select procedure using left join and display more than one data in a single date
我正在做一个小型旅馆预订项目。我尝试在网格上创建一个日历列表,显示一个月中的所有日期,日期旁边是旅馆的交易详情(预订详情或预订详情)。
这是我的示例数据:
交易table
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
这是我想要的输出:
Select 程序
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
我的select程序在一个日期只能获取一个数据。
这是我的程序的实际输出
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;
并将此过程调用到我的主要 select 过程。
这是我正在处理的 select 程序。
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
...
我的select程序在一个日期只能获取一个数据。
这是所需的输出
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
...
您在 select 中使用 :COMPLETE_DATE
是相当可疑的,即使它在 select 的开头是 NULL
。我什至不知道 Firebird 会填充并应用 mid-execution 中的变量,就好像它是一个别名一样。此外,sub-select 本身看起来很奇怪,我不确定您要用它做什么。
从小测试(在 5 月 1 日添加带有 SALES_DATEFROM
的记录)来看,这似乎是由于评估顺序:在 WHERE
子句中 sub-select :COMPLETE_DATE
变量仍然具有前一行的值(这可能是您将其定义为 1 + DAYS_IN_MONTH.D
的原因)。由于 5 月 1 日是第一行,因此 :COMPLETE_DATE
此时仍是 NULL
。然而,在 5 月 18 日,您有两条记录(房间 1 和房间 2),但是当评估房间 2 的记录时,连接条件不再适用,因为 :COMPLETE_DATE
值已在记录时更新房间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
会成功,而且在我看来,也更容易理解。
如此简单的任务不需要那么复杂的代码:它只会让您感到困惑。
似乎您只需要一个原始 loop-based 存储过程来生成时间跨度(最左边的列)中的所有日期,然后您只需对该 SP 执行 LEFT JOIN
预订 table。像
Select D, SALESPARTICULAR || ' ' || SALES_DATEFROM || ' - ' || SALES_DATETO
From DAYS_IN_MONTH(...)
LEFT JOIN Transactions
ON D BETWEEN SALES_DATEFROM AND SALES_DATETO
我正在做一个小型旅馆预订项目。我尝试在网格上创建一个日历列表,显示一个月中的所有日期,日期旁边是旅馆的交易详情(预订详情或预订详情)。
这是我的示例数据:
交易table
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
这是我想要的输出:
Select 程序
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
我的select程序在一个日期只能获取一个数据。
这是我的程序的实际输出
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;
并将此过程调用到我的主要 select 过程。
这是我正在处理的 select 程序。
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
...
我的select程序在一个日期只能获取一个数据。
这是所需的输出
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
...
您在 select 中使用 :COMPLETE_DATE
是相当可疑的,即使它在 select 的开头是 NULL
。我什至不知道 Firebird 会填充并应用 mid-execution 中的变量,就好像它是一个别名一样。此外,sub-select 本身看起来很奇怪,我不确定您要用它做什么。
从小测试(在 5 月 1 日添加带有 SALES_DATEFROM
的记录)来看,这似乎是由于评估顺序:在 WHERE
子句中 sub-select :COMPLETE_DATE
变量仍然具有前一行的值(这可能是您将其定义为 1 + DAYS_IN_MONTH.D
的原因)。由于 5 月 1 日是第一行,因此 :COMPLETE_DATE
此时仍是 NULL
。然而,在 5 月 18 日,您有两条记录(房间 1 和房间 2),但是当评估房间 2 的记录时,连接条件不再适用,因为 :COMPLETE_DATE
值已在记录时更新房间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
会成功,而且在我看来,也更容易理解。
如此简单的任务不需要那么复杂的代码:它只会让您感到困惑。
似乎您只需要一个原始 loop-based 存储过程来生成时间跨度(最左边的列)中的所有日期,然后您只需对该 SP 执行 LEFT JOIN
预订 table。像
Select D, SALESPARTICULAR || ' ' || SALES_DATEFROM || ' - ' || SALES_DATETO
From DAYS_IN_MONTH(...)
LEFT JOIN Transactions
ON D BETWEEN SALES_DATEFROM AND SALES_DATETO