【问题标题】:ColdFusion Dynamic SQL with cfif带有 cfif 的 ColdFusion 动态 SQL
【发布时间】:2017-12-08 20:44:27
【问题描述】:

我正在尝试编写一个查询,该查询将接受从另一个页面传递的 4 个可能参数中的 1 个。用户将选择这些参数之一进行搜索,然后查询将根据传递的参数评估选择了哪些参数。我正在尝试使用 cfif 来完成此操作,但我必须遗漏一些东西。也许是一个 cfelse 和 OR,或者我离题了。这会更好作为cffunction吗?我收到一个错误“变量 DivisionCode”未定义。谢谢。

<cfquery name="Summary" datasource="dsn">
    SELECT
        *
    FROM
        disposal
    WHERE 1=1

    <cfif DivisionCode NEQ "false">
    AND DivisionCode = <cfqueryparam value="#url.DivisionCode#" 
   cfsqltype="cf_sql_varchar">
   </cfif>
   <cfif DistrictCode NEQ "false">
    AND DistrictCode = <cfqueryparam value="#url.DistrictCode#" 
   cfsqltype="cf_sql_varchar">
   </cfif>
   <cfif SiteCode NEQ "false">
    AND SiteCode = <cfqueryparam value="#url.SiteCode#" 
   cfsqltype="cf_sql_varchar">
  </cfif>
  <cfif RegionCode NEQ "false">
    AND RegionCode = <cfqueryparam value="#url.RegionCode#" 
  cfsqltype="cf_sql_varchar">
  </cfif>
  ORDER By
    CYear DESC
  </cfquery>

【问题讨论】:

  • 如果问题是未定义的变量,请查看您认为定义它的位置。
  • 如果您在这里处理布尔逻辑,我会在尝试将它们与动态 SQL 一起使用之前验证这些变量。此外,在cfif 中设置变量的范围,并在cfqueryparam 标记中设置maxlength。我从来都不喜欢在查询中直接使用 URL 或 FORM 范围内的任何内容。 cfqueryparam 可以做很多事情来防止注射,应该绝对使用,但它并不总是能防止一切。
  • 正如丹所说,这些变量是如何传递的?如果您在使用它们之前对其进行验证,请使用structKeyExists 来查看变量是否存在。

标签: coldfusion


【解决方案1】:

我会查看变量范围并检查以确保变量存在。所以,让我们看看你的一个条件。

<cfif StructKeyExists(url,"DivisionCode") AND url.DivisionCode NEQ "false">
   AND DivisionCode = <cfqueryparam value="#url.DivisionCode#" cfsqltype="cf_sql_varchar">
 </cfif>

添加“网址”。 “DivisionCode”之前的前缀将指定您正在查找变量的范围。这不会真正帮助直接解决您的问题,但它会使您的代码更清晰,错误消息更有帮助。

首先添加 StructKeyExists() 检查以确保该变量在 URL 中可用。根据您编写代码的方式,我猜您不想通过未包含的 URL 变量进行过滤,因此可以解决此问题。

只要在每个 cfif 上做同样的事情,你就应该是正确的。

【讨论】:

    【解决方案2】:

    我想到了两个选项:您可以让它像包含一样工作,也可以将其作为函数调用。

    隔离包含(不太常见)

    your_query.cfm

    <!--- declaring possible incoming parameters --->
    <cfparam name="attributes.datasource"   type="string" default="dsn">
    <cfparam name="attributes.divisionCode" type="string" default="">
    <cfparam name="attributes.districtCode" type="string" default="">
    <cfparam name="attributes.siteCode"     type="string" default="">
    <cfparam name="attributes.regionCode"   type="string" default="">
    
    <!--- declaring outgoing variable --->
    <cfparam name="attributes.variable"     type="string" default="your_query">
    
    <!--- retrieve result --->
    <cfquery name="Summary" datasource="#attributes.datasource#">
        SELECT
            *
        FROM
            disposal
        WHERE 1=1
    
        <cfif len(attributes.divisionCode) gt 0>
            AND DivisionCode = <cfqueryparam value="#attributes.divisionCode#" cfsqltype="cf_sql_varchar">
        </cfif>
        <cfif len(attributes.districtCode) gt 0>
            AND DistrictCode = <cfqueryparam value="#attributes.districtCode#" cfsqltype="cf_sql_varchar">
        </cfif>
        <cfif len(attributes.siteCode) gt 0>
            AND SiteCode = <cfqueryparam value="#attributes.siteCode#" cfsqltype="cf_sql_varchar">
        </cfif>
        <cfif len(attributes.regionCode) gt 0>
            AND RegionCode = <cfqueryparam value="#attributes.regionCode#" cfsqltype="cf_sql_varchar">
        </cfif>
    
        ORDER BY
            CYear DESC
    </cfquery>
    
    <!--- set outgoing variable --->
    <cfset caller[attributes.variable] = Summary>
    

    invoking.cfm

    <cfmodule divisionCode="foo" regionCode="bar" variable="my_query" template="your_query.cfm">
    <cfdump var="#my_query#">
    
    <!--- or --->
    
    <cfset params = {}>
    <cfset params.siteCode = "bla">
    <cfif structKeyExists(url, "regionCode")>
        <cfset params.regionCode = url.regionCode>
    </cfif>
    
    <cfmodule attributeCollection="#params#" template="your_query.cfm">
    <cfdump var="#your_query#">
    
    <!--- etc. --->
    

    &lt;cfmodule&gt; 标记将其内容隔离开来,这意味着调用模板 (invoking.cfm) 不能看到 your_query.cfm 内的任何变量(分配给 caller 范围的变量除外)。这种方法基本上是原生 CF 标签如 &lt;cfhttp&gt;&lt;cffile&gt; 所做的。


    功能(更常见)

    <cffunction name="yourQuery" access="public" output="false" returnType="query">
    
        <!--- declaring possible incoming parameters --->
        <cfargument name="datasource"   type="string" default="dsn">
        <cfargument name="divisionCode" type="string" default="">
        <cfargument name="districtCode" type="string" default="">
        <cfargument name="siteCode"     type="string" default="">
        <cfargument name="regionCode"   type="string" default="">
    
        <!--- retrieve result (the local. scope makes the variable exist in this function only) --->
        <cfquery name="local.Summary" datasource="#arguments.datasource#">
            SELECT
                *
            FROM
                disposal
            WHERE 1=1
    
            <cfif len(arguments.divisionCode) gt 0>
                AND DivisionCode = <cfqueryparam value="#arguments.divisionCode#" cfsqltype="cf_sql_varchar">
            </cfif>
            <cfif len(arguments.districtCode) gt 0>
                AND DistrictCode = <cfqueryparam value="#arguments.districtCode#" cfsqltype="cf_sql_varchar">
            </cfif>
            <cfif len(arguments.siteCode) gt 0>
                AND SiteCode = <cfqueryparam value="#arguments.siteCode#" cfsqltype="cf_sql_varchar">
            </cfif>
            <cfif len(arguments.regionCode) gt 0>
                AND RegionCode = <cfqueryparam value="#arguments.regionCode#" cfsqltype="cf_sql_varchar">
            </cfif>
    
            ORDER BY
                CYear DESC
        </cfquery>
    
        <!--- return result --->
        <cfreturn local.Summary>
    </cffunction>
    

    invoking.cfm

    <cfset my_query = yourQuery("dsn", "foo", "", "bar")>
    <cfdump var="#my_query#">
    
    <!--- or --->
    
    <cfset your_query = yourQuery(
        datasource: "dsn",
        siteCode: "bla"
        regionCode: ( structKeyExists(url, "regionCode") ? url.regionCode : "" )
    )>
    <cfdump var="#your_query#">
    
    <!--- etc. --->
    

    这应该让您对自己可以实现的目标有所了解。

    【讨论】:

    • 感谢您的努力,亚历克斯。很好的解释。这有助于解决我的问题。
    猜你喜欢
    • 2022-05-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    相关资源
    最近更新 更多