透過 CONSTRUCT 陳述式產生 SQL WHERE 子句時,執行環境需要知道的不只是資料庫的類型,還需要知道欄位的資料型別

資料庫連線必須在 CONSTRUCT 之前

資料庫類型由目前的資料庫連線決定。無論使用單一資料庫連線模型還是多連線模型連接到不同類型的資料庫,都必須在 CONSTRUCT 陳述式之前切換到目標資料庫。也就是說,DATABASECONNECT TOSET 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。

原文:https://4js.com/ask-reuben/ig-302/  ·  有任何 Genero 技術問題或翻譯疑問,歡迎來信 support@t100.app