2013-04-22 97 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