我們有前端應用程式,用戶可以在其中輸入客戶和/或 PO 以檢索資料。例如,如果用戶想要檢索客戶的所有 PO,他將在 PO 欄位中輸入“%”。如果用戶想要檢索所有資料,他將在每個欄位中輸入“%”。我正在嘗試這個,但它不起作用

SELECT *
FROM PO_INFO
WHERE customer_id = case when '%' then customer_id else 'Macys' end
AND purchase_order = case when '%' then purchase_order else '79124' end
我錯過了什么?
uj5u.com熱心網友回復:
您不應該(有人會說絕對不能)只是將用戶輸入的搜索值作為文字插入到 SQL 查詢中。那是,
AND purchase_order = case when '%' then purchase_order else '79124' end
... 不會很好地執行或擴展,因為在 Oracle 看來,每個搜索都像一個全新的 SQL 查詢,必須進行決議和優化(即“硬決議)。這是一個昂貴的程序,也需要大量的閂鎖,這意味著嘗試同時運行搜索的多個用戶將不得不相互等待。
相反,您應該使用系結變數來構造 SQL。所以,
AND purchase_order = :1 -- or something. We'll discuss the exact logic later...
:1 是一個系結變數,它是代碼在提交查詢時將提供的值的占位符。現在,進行搜索的每個人都使用相同的查詢(只是每個人為系結變數提供不同的值)。不再有過度的硬決議和避免性能災難。
但是,這是下一個問題。一個查詢意味著它只能被硬決議一次(很好),但這也意味著每個人都使用相同的執行計劃運行。但在這樣的搜索中,一種尺寸并不適合所有人。假設 Oracle 提出的執行計劃使用列 'ABC' 上的索引。如果用戶沒有為列“ABC”提供系結變數值,則仍將遵循該執行計劃,但結果很糟糕。
所以,我們真正想要的是為每組有值或沒有值的系結變數提供一個 SQL,而不是為每組不同的文字搜索值提供一個 SQL。
從以下字串開始在代碼中構建您的 SQL:
SELECT * FROM PO_INFO WHERE 1=1
然后,為每個搜索條件添加這個(如果值為 %)
AND (:1 IS NULL) -- and pass `NULL`, not "%" as the value for :1
(除此之外:這種情況的原因,本質上NULL IS NULL是為了使必須傳入的系結變數的數量和順序始終相同,無論最終用戶做什么或不給你一個值這使得提交某些語言的 SQL 變得更加容易,例如 PL/SQL)。
如果搜索條件不是 %,則添加:
AND (customer_id /* or whatever column */ = :1) -- and pass the user-entered value
因此,例如,如果用戶為customer_idandpo_date但 not指定了值purchase_order,您的最??終 SQL 可能如下所示:
SELECT *
FROM PO_INFO
WHERE 1=1
AND customer_id = :1
AND po_date := 2
AND :3 IS NULL -- this is purchase order and :3 you will pass as null
如果您執行所有這些操作,您將獲得最少的硬決議和每次搜索的最佳執行計劃。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/428254.html
上一篇:Spark中笛卡爾連接和BroadcastNestedLoop連接的區別
下一篇:特殊條件的內連接
