2013-04-22 63 views
0

我目前正在尋找一個搜索功能,用戶可以通過主持演出的樂隊名稱或演出本身的位置來搜索演出。我遇到的問題是搜索的位置部分,我想搜索我存儲的城鎮,縣和國家/地區字段,以便說如果演出地點是「英格蘭約克郡的利茲」,用戶搜索「英語「它會匹配,因爲它發現它在國家領域。如果他們因爲在利茲的比賽而搜索「編輯」,那麼也是一樣。在查詢中搜索多個列

我知道這可以通過在查詢中使用Group By方法來實現,但是,我正在尋找有關最佳實踐的建議,以及如何應用它,因爲我之前沒有使用Group By。

這裏是不正確的查詢我開始:

<cfquery datasource="#datasource#" name="findgigs"> 
    Select artist_id, gig_id, gig_artistid, gig_town, gig_county, gig_country 
    From artists, gigs 
    Where artist_id = gig_artistid 
    <cfif IsDefined("URL.search")> 
     And gig_town LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#%> 
     Or gig_county LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#%> 
     Or gig_country LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#%> 
    </cfif> 
</cfquery> 

正如我在運行查詢後發現(事先應已知)返回很多重複。然而,看着這個查詢,你可以看到我試圖獲得它的方式完全是錯誤的。任何關於如何改善這方面的知識或建議,將不勝感激。

+0

「我一直在尋找最佳實踐的建議」不要用'選擇*':) – Travis 2013-04-22 12:06:27

+0

好點,現在不適合編輯。 – Banny 2013-04-22 12:15:47

+0

如果你只是做了一個獨特的選擇? – 2013-04-22 12:53:44

回答

2

您的WHERE子句不包含圍繞您的OR的任何分組。這在檢查縣或國家時會導致初始標準被忽略。由於您使用ANSI 89語法來處理您的連接(不指定INNER JOIN),因此這會破壞您的連接。

有幾種方法可以解決這個問題。如果你想繼續使用ANSI 89:

<cfquery datasource="#datasource#" name="findgigs"> 
    Select artist_id, gig_id, gig_artistid, gig_town, gig_county, gig_country 
    From artists, gigs 
    Where artist_id = gig_artistid 
    <cfif IsDefined("URL.search")> 
     And (gig_town LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#%"> 
     Or gig_county LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#%"> 
     Or gig_country LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#%">) 
    </cfif> 
</cfquery> 

正如你看到的,我所做的有添加「(下稱」「和」和之後「),」最後的cfparam後。這將把這些標準組合在一起,以便對所有三個標準使用artist_id標準(防止出現額外的結果)。

如果你想改變SQL明確定義您的加入(ANSI 92):

<cfquery datasource="#datasource#" name="findgigs"> 
    Select artist_id, gig_id, gig_artistid, gig_town, gig_county, gig_country 
    From artists 
    Inner Join gigs ON artist_id = gig_artistid 
    <cfif IsDefined("URL.search")> 
     Where gig_town LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#%"> 
     Or gig_county LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#%"> 
     Or gig_country LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#%"> 
    </cfif> 
</cfquery> 
+0

這工作完美!非常感謝,我應該開始擴大我的SQL知識,並可能使用INNER JOIN更多,我猜內部連接是一種更有效的方式來運行查詢? – Banny 2013-04-24 09:44:46

+0

不,它使用[ANSI-92](http://en.wikipedia.org/wiki/SQL-92)語法(首選)而不是ANSI-89(過時)完全一樣。連接方式的改變並不能解決問題。正如Mike所說的,當混合AND和OR操作符讓數據庫知道你想如何評估表達式時,你應該總是使用括號。否則,數據庫將使用[自己的優先規則](http://msdn.microsoft.com/zh-cn/library/bb387132.aspx),結果通常不是您想要的。 – Leigh 2013-04-24 13:25:18

3
<cfquery datasource="#datasource#" name="findgigs"> 
    SELECT artist_id 
    FROM artists 
    WHERE artist_id IN 
     ( 

      SELECT gig_artistid 
      FROM gigs 
      WHERE 1 = 0 
      <cfif structKeyExists(url,'search')> 
      OR gig_town LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#"> 
      OR gig_county LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#"> 
      OR gig_country LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#"> 
     </cfif> 
    ) 
</cfquery> 
  1. 如果你擔心重複值,此子查詢將有助於補救措施,不進行分組。

  2. 新增cfqueryparam作爲一個最佳實踐,以幫助防止SQL注入

用於查詢的邏輯是「作秀沒什麼開始」,然後如果你的搜索定義,則或將允許踢結果顯示。

選項#2

<cfquery datasource="#datasource#" name="findgigs"> 
    SELECT artist_id 
    FROM artists 
    <cfif structKeyExists(url,'search')> 
    WHERE artist_id IN 
     ( 
      SELECT gig_artistid 
      FROM gigs 
      WHERE gig_town LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#"> 
      OR  gig_county LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#"> 
      OR  gig_country LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#URL.search#"> 
     ) 
    </cfif> 
</cfquery> 

開始通過顯示所有。如果添加了搜索條件,它將開始過濾掉結果以包含您的搜索條件。

+0

我使用了cfqueryparam,只是忘記包含在我上面的代碼中。現在編輯。而我的查詢工作方式是,如果搜索未定義,它將返回存儲的所有記錄,幾乎充當「全部列出」選項。 – Banny 2013-04-22 12:39:58

+0

好的,很簡單。將1 = 0更改爲1 = 1。這將顯示所有。您可能還想考慮「或」爲「和」。 1 = 1將始終顯示所有記錄,即使應用了標準。如果你改變了cfif中的第一個或者右邊,那麼就會這樣做......我將更新我的代碼以顯示第二個選項。 – steve 2013-04-22 12:44:09

+0

乾杯,非常有幫助。我現在試試看看是否適合我。 – Banny 2013-04-22 12:47:19