透過 CONSTRUCT 陳述式產生 SQL WHERE 子句時,執行環境需要知道的不只是資料庫的類型,還需要知道欄位的資料型別。
資料庫連線必須在 CONSTRUCT 之前
資料庫類型由目前的資料庫連線決定。無論使用單一資料庫連線模型還是多連線模型連接到不同類型的資料庫,都必須在 CONSTRUCT 陳述式之前切換到目標資料庫。也就是說,DATABASE、CONNECT TO 或 SET CONNECTION 陳述式必須在 CONSTRUCT 陳述式之前執行,以確保執行環境知道該為哪種資料庫語法產生 WHERE 子句。
formonly 欄位必須搭配 TYPE
執行環境同樣需要知道欄位的資料型別。如果欄位定義為 formonly,執行環境無法知道該欄位的資料型別。因此,當使用 formonly 時,務必同時使用 TYPE 關鍵字來告知執行環境欄位的資料型別。
僅僅使用 DATEEDIT 這樣的小工具,並不足以讓執行環境知道欄位是日期型別——你必須明確使用 TYPE 關鍵字(或者不使用 formonly),這樣執行環境才能知道應為哪種資料型別產生 WHERE 子句。
範例說明
為了說明這個差異,以下是一個示範程式。幾個要點:
CONNECT TO ":memory:+driver='dbmsqt'" 這行連接到記憶體中的 SQLite 資料庫。這行必須在 CONSTRUCT 陳述式之前,執行環境才知道使用的是 SQLite。
在表單中,注意兩個 DATEEDIT 欄位的定義——一個有 TYPE date,一個沒有:
DATEEDIT f02 = formonly.field2;
DATEEDIT f03 = formonly.field3 TYPE DATE;
執行程式後,點選今天的日期並按下確定,注意產生的 WHERE 子句:
scr.field1='03/11/2025' and scr.field2='03/11/2025' and scr.field3='2025-11-03'
注意 field3(有指定 TYPE 的 DATEEDIT)和 field2(沒有 TYPE 的 DATEEDIT)產生的 WHERE 子句有何不同:
field3使用了正確的日期語法('2025-11-03')field2的 WHERE 子句和field1(普通字元欄位的 EDIT)一樣,都是日期字串格式('03/11/2025')
如果你的程式碼中使用了 formonly,建議遵守的程式碼規範是:每個 formonly 欄位都必須加上 TYPE 子句。否則,產生的 WHERE 子句可能無法回傳你預期的查詢結果。
完整程式碼範例
askreuben302.4gl
#! askreuben302.4gl
MAIN
DEFINE program_name STRING
DEFINE where_part STRING
WHENEVER ANY ERROR STOP
DEFER INTERRUPT
DEFER QUIT
OPTIONS FIELD ORDER FORM
OPTIONS INPUT WRAP
CONNECT TO ":memory:+driver='dbmsqt'"
LET program_name = base.Application.getProgramName()
CALL ui.Dialog.setDefaultUnbuffered(TRUE)
CLOSE WINDOW SCREEN
OPEN WINDOW w WITH FORM program_name ATTRIBUTES(TEXT = program_name)
WHILE TRUE
CONSTRUCT BY NAME where_part ON scr.field1, scr.field2, scr.field3
ON ACTION today
DISPLAY TODAY TO field1
DISPLAY TODAY TO field2
DISPLAY TODAY TO field3
ON ACTION less
DISPLAY "<" || TODAY TO field1
DISPLAY "<" || TODAY TO field2
DISPLAY "<" || TODAY TO field3
ON ACTION between
DISPLAY (TODAY - 1) || ".." || (TODAY + 1) TO field1
DISPLAY (TODAY - 1) || ".." || (TODAY + 1) TO field2
DISPLAY (TODAY - 1) || ".." || (TODAY + 1) TO field3
ON ACTION in
DISPLAY (TODAY - 1) || "|" || (TODAY + 1) TO field1
DISPLAY (TODAY - 1) || "|" || (TODAY + 1) TO field2
DISPLAY (TODAY - 1) || "|" || (TODAY + 1) TO field3
END CONSTRUCT
IF int_flag THEN
EXIT WHILE
END IF
DISPLAY where_part
MESSAGE where_part
END WHILE
END MAIN
askreuben302.per
#! askreuben302.per
LAYOUT
GRID
{
Edit [f01 ]
DateEdit (formonly) [f02 ]
DateEdit (formonly+type)[f03 ]
}
END
END
ATTRIBUTES
EDIT f01 = formonly.field1;
DATEEDIT f02 = formonly.field2;
DATEEDIT f03 = formonly.field3 TYPE DATE;
INSTRUCTIONS
SCREEN RECORD scr(formonly.field1, formonly.field2, formonly.field3)
歷史背景
在過去,通用程式碼在這方面有困難,因為通用表單使用 formonly,而且因為不知道資料型別,無法使用 TYPE。在 1990 年代,fgl_zoom 的前身有一些特殊處理程式碼來應對不同資料型別的問題。隨著通用對話框和動態建立表單功能的引入,fgl_zoom 已經不再有這個問題,因為它產生的表單是帶有 TYPE 的 formonly。