跳轉到

指令碼開發 / SQL 構造 DFF.SQL

DFF.SQL(...) 用於構造帶引數的 SQL,避免透過字串拼接插入使用者輸入。多數 SQL 聯結器已經內建此能力,可以直接呼叫 conn.query(sql, sql_params=...) 或 conn.non_query(...)。

只有需要顯式格式化 SQL 用於除錯,或呼叫方必須接收最終 SQL 字串時,才需要單獨呼叫 DFF.SQL(...)。

引數與佔位符

引數 型別 必須 / 預設值 說明
sql str 必須 包含引數佔位符的 SQL 語句
sql_params list None 按佔位符順序提供的 SQL 引數
佔位符 含義 示例結果
? 值引數,會轉義並加引號 'user-001'
?? 識別符號或 SQL 片段,不加引號 users
示例
1
2
3
4
5
sql = DFF.SQL(
    'SELECT * FROM ?? WHERE id = ?',
    ['users', 'user-001'],
)
# SELECT * FROM users WHERE id = 'user-001'

?? 不會保護不可信輸入

使用者輸入必須放入 ?。表名、欄位名等識別符號只有在來自允許列表或可信配置時才能放入 ??,不得透過 f-string 或字串拼接插入 SQL 值。

引數展開

陣列引數會自動展開為多個值,二維陣列會展開為多行值:

陣列展開
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
rows = db.query(
    'SELECT * FROM ?? WHERE status IN (?)',
    ['demo', ['error', 'warning']],
)
# SELECT * FROM demo WHERE status IN ('error', 'warning')

affected_rows = db.non_query(
    'INSERT INTO ?? (id, name) VALUES ?',
    ['demo', [[1, 'a'], [2, 'b']]],
)
# INSERT INTO demo (id, name) VALUES (1, 'a'), (2, 'b')

字典引數會展開為多個賦值表示式:

字典展開
1
2
3
4
5
affected_rows = db.non_query(
    'INSERT INTO ?? SET ?',
    ['demo', {'id': 1, 'name': 'a'}],
)
# INSERT INTO demo SET id = 1, name = 'a'

執行動態寫入或刪除 SQL 前,應再次確認目標表和過濾條件。