2017-03-10 72 views
0

我想編寫一個搜索查詢。我有以下情況。如何在SQL中編寫搜索查詢

有3個條件(ID,NAME,CITY)用於搜索結果。 例如:

  • 如果用戶輸入ID = 123,那麼所有與ID的行= 123應該 而不管名稱和城市
  • 的如果用戶輸入ID = 123 和名稱=「SAM取出',那麼不管城市如何,都應該獲取ID = 123且名稱='SAM' 的所有行
  • 如果用戶輸入ID = 123,name ='SAM'且城市='NY',則全部應該獲取具有確切的 匹配的行。
+1

添加一些示例表格數據和預期結果 - 以及格式化文本。同時向我們展示您當前的查詢嘗試。 – jarlh

+0

@GordonLinoff老實說,我不認爲它有矛盾。如果只輸入一個ID,則返回具有該ID的所有行,然後另外兩個只是縮小搜索結果。 – David

+1

可能[重複](http://stackoverflow.com/questions/17681428/issue-with-oracle-bind-variables-not-using-index-properly/) – tbone

回答

0

Gordon Linoff提供的答案肯定是好的,可行的,直接的,但它沒有解決像您這樣的情況下的性能問題。

也就是說,您正在搜索的表格可能非常大,並且有各種索引(例如,在您的情況下,NAME上的索引和CITY上的另一個索引)。在這種情況下,一個簡單的靜態SQL方法可能會使用一個或另一個索引,並且在沒有提供它所使用的索引標準的情況下性能較差。 (我知道Oracle 11g引入了自適應光標共享 - 雖然我還沒有看到它真的有用,但我相信這可能會讓我的回答過時,並會讓我的回答過時,但我沒有看到它真的工作得很好,我歡迎評論)。

無論如何,如果你沒有11g和/或不想依賴大量自適應光標共享,我認爲目前編寫此類搜索查詢的最佳做法是使用REF CURSOR。就像這樣:

-- Create a table to query from 
CREATE TABLE matt1 (id number, name varchar2(30), city varchar2(30)); 

CREATE OR REPLACE PACKAGE matt_query_pkg AS 
    FUNCTION get_results (p_id NUMBER, p_name VARCHAR2, p_city VARCHAR2) RETURN SYS_REFCURSOR; 
END matt_query_pkg; 

CREATE OR REPLACE PACKAGE BODY matt_query_pkg AS 
    FUNCTION get_results (p_id NUMBER, p_name VARCHAR2, p_city VARCHAR2)RETURN SYS_REFCURSOR IS 
    l_rc SYS_REFCURSOR; 
    l_sql VARCHAR2(32000); 
    BEGIN 
    l_sql := 'SELECT id, name, city FROM matt1 WHERE 1=1'; 
    if p_id IS NULL THEN 
     l_sql := l_sql || ' AND (1=1 OR :b_id IS NULL)'; 
    else 
     l_sql := l_sql || ' AND (id = :b_id)'; 
    end if; 

    if p_name IS NULL THEN 
     l_sql := l_sql || ' AND (1=1 OR :b_name IS NULL)'; 
    else 
     l_sql := l_sql || ' AND (name = :b_name)'; 
    end if; 

    if p_city IS NULL THEN 
     l_sql := l_sql || ' AND (1=1 OR :b_city IS NULL)'; 
    else 
     l_sql := l_sql || ' AND (id = :b_city)'; 
    end if; 

    dbms_output.put_line('Executing:'); 
    dbms_output.put_line(l_sql); 

    OPEN l_rc FOR l_sql USING p_id, p_name, p_city; 

    RETURN l_rc; 
    END get_results; 
END matt_query_pkg; 

在一個例子情況下只有IDNAME標準給出,它會產生這樣的SQL:

SELECT id, name, city 
FROM matt1 
WHERE 1=1 
AND (id = :b_id) 
AND (name = :b_name) 
AND (1=1 OR :b_city IS NULL) 

Oracle的優化會分解出(1=1 OR :b_city IS NULL)條款(因爲它知道它始終是true),留下一個SQL,然後可以專門針對給定的條件進行優化。

注意:將在所有(1=1 OR :b_city IS NULL)子句中的一點是要保持綁定變量的數目不變,所以你可以隨時使用運行搜索:

OPEN l_rc FOR l_sql USING p_id, p_name, p_city; 

如果沒有擺在那(1=1 OR...)子句,對於空/非空輸入參數的每個可能組合,您必須有不同的OPEN..FOR語句。

下面是一些代碼來測試它,以供參考:

-- Test it 
insert into matt1 values (1, 'Fred', 'New York'); 
insert into matt1 values (2, 'Fred', 'Philadelphia'); 
insert into matt1 values (3, 'John', 'Philadelphia'); 
insert into matt1 values (4, 'Mark', 'Philadelphia'); 
insert into matt1 values (5, 'Mark', 'Chicago'); 
commit; 

declare 
    l_rc SYS_REFCURSOR; 
    l_id NUMBER; 
    l_name VARCHAR2(30); 
    l_city VARCHAR2(30); 
begin 
    l_rc := matt_query_pkg.get_results (NULL, 'Fred', NULL); 
    loop 
    fetch l_rc INTO l_id, l_name, l_city; 
    exit when l_rc%NOTFOUND; 
    dbms_output.put_line ('Found: ' || l_id || ', ' || l_name || ', ' || l_city); 
    end loop; 
end; 
3

典型的方法是這樣的:

where (id = v_id or v_id is null) and 
     (name = v_name or v_name is null) and 
     (city = c_city or v_city is null) 
+0

這更準確。但正如第一條評論所說,海報應該提供更多的信息,包括他們自己的嘗試。 – unleashed

-1

我認爲這將工作:

SELECT * 
    FROM myTable AS t1 
    WHERE t1.ID = 123 
      OR (
        t1.ID = 123 
        AND t1.NAME = 'SAM' 
       ) 
      OR (
        t1.ID = 123 
        AND t1.NAME = 'SAM' 
        AND t1.CITY = 'NY' 
       ) 
0

儘管這是一個相對簡單的解決方案相對簡單的例子,我很猶豫,贊同的試圖建立一個通用的SQL的方法聲明來處理所有可能性。我已經看到了一些非常複雜的例子,雖然它在功能上起作用,但優化器並不希望獲得良好的基數估計,並且隨後還有一個很好的執行計劃。 SQL本質上不是過程語言;而PL/SQL或Java或C#或以往任何時候都是如此。因此,善於條件:)那麼,爲什麼不這樣做,(邏輯)

如果只指定ID,然後運行該SQL

select * from table where id = v_id; 
; 

如果ID和名稱指定然後運行這個SQL

select * from table 
where id = v_id 
and name = v_name 
; 

如果再指定三個運行該SQL

select * from table 
where id = v_id 
and name = v_name 
and city = v_city 

結果是你有三個非常容易優化的SQL語句,而不是一個困難的語句。

現在的論點總是,「但我有一些可能可查詢的領域,有太多的組合」。這是您賺取工資的地方(或諮詢費!)。您需要務實並將其分解爲查詢的「集合」,以便在每種可能的組合的SQL和一個非常複雜的不可優化的SQL之間進行合理的折衷。 我希望這是有道理的。