2014-01-27 67 views
0

我已經創建了一個表來滿足一些客戶的需求,並且必須針對要存儲在表中的數據編寫一個查詢。我無法找出編寫我的查詢的最佳方式。無法找出查詢

我的表的結構類似於:

c1 c2_lower_limit c2_upper_limit c3_lower_limit c3_upper_limit rate operator 
1 0    10000   0    20000   10  AND 
1 10000   50000   20000   30000   20  OR 
1 50000   NULL    30000   NULL    30  OR 
2 0    10000   0    20000   10  AND 
2 10000   50000   20000   30000   20  OR 
2 50000   NULL    30000   NULL    30  OR 

用戶指定的C1一個值,然後爲C2C3(只是一個用於C2值和一個用於C3)的值。假設我必須返回費率列作爲輸出。表格結構中的最後一列是OPERATOR,它告訴我C2C3值應該是AND還是OR ed。

我在確定要使用的操作器時遇到問題。用戶可以根據自己的判斷選擇任意值作爲下限和上限。我嘗試將我的操作員選擇僅限於一個組 - 我們假設C2,但那不是正確的,因爲我需要評估用戶輸入的所有血管數據以獲得正確的操作員。

假設用戶爲c2輸入值0,併爲c1 = 1爲c3輸入值25000。由於c3的值對應於操作數值爲OR的條目,因此我應該使用c2和c3的限制值OR。總之,如果找到一條帶有OR運營商的記錄,我必須要OR的c2和c3組。

您可以檢查SQLFiddle的表結構http://www.sqlfiddle.com/#!4/f9bf6/11

+1

你的查詢在哪裏是次優的形式? – GolezTrol

+0

Hi @GolezTrol,我錯過了在SQLFiddle窗口中發佈我的查詢。我現在發佈了它。我說錯了,說它不是最佳的,它甚至不會返回正確的結果。 – Incognito

回答

1

一個快速和骯髒的解決辦法是在operator字段中添加條件。

使用:符號來表示傳遞的參數:

SELECT * 
FROM my_table 
WHERE c1 = :c1 
AND ((operator = 'AND' 
     AND 
     (:c2 BETWEEN c2_lower_limit AND c2_upper_limit OR 
      (:c2 >= c2_lower_limit AND c2_upper_limit IS NULL) OR 
      (c2_lower_limit IS NULL AND :c2 < c2_upper_limit) 
     AND 
     (:c3 BETWEEN c3_lower_limit AND c3_upper_limit OR 
      (:c3 >= c3_lower_limit AND c3_upper_limit IS NULL) OR 
      (c3_lower_limit IS NULL AND :c3 < c3_upper_limit) 
     ) 
     OR 
     (operator = 'OR' 
     AND 
     (:c2 BETWEEN c2_lower_limit AND c2_upper_limit OR 
      (:c2 >= c2_lower_limit AND c2_upper_limit IS NULL) OR 
      (c2_lower_limit IS NULL AND :c2 < c2_upper_limit) 
     OR 
     (:c3 BETWEEN c3_lower_limit AND c3_upper_limit OR 
      (:c3 >= c3_lower_limit AND c3_upper_limit IS NULL) OR 
      (c3_lower_limit IS NULL AND :c3 < c3_upper_limit) 
     ) 
     ) 

編輯:
注意,有很多代碼口是心非處理null s的一個between操作。如果你可以改變數據庫,我會添加一個幫助函數來做到這一點:

CREATE OR REPLACE FUNCTION null_safe_between 
(eval NUMBER, lower NUMBER, upper NUMBER) 
RETURN BOOLEAN 
DETERMINISTIC 
BEGIN 
    RETURN eval BETWEEN lower_limit AND upper_limit OR 
      (eval >= lower_limit AND upper_limit IS NULL) OR 
      (lower_limit IS NULL AND eval < upper_limit); 
END;