ColdFusion参数化查询

时间:2014-11-20 21:30:15

标签: mysql coldfusion

我有一个查询,我运行以填充我试图参数化的CFChart:

<cfquery name="total" datasource="#datasource#">
    SELECT *
    FROM   closed_tickets
    WHERE  MONTH(closed_date) = #month# 
    AND    YEAR(closed_date) = #dateFormat(theMonth,"yyyy")# 
    AND    technician_id = #techID#
 </cfquery>

以下是我的尝试:

<!---Open tickets from chosen year where technician is active --->
<cfquery name="total" datasource="#datasource#">          
    SELECT *
    FROM   closed_tickets
    WHERE  MONTH(closed_date) = <CFQUERYPARAM Value="#month#"> 
    AND    YEAR(closed_date) = #dateFormat(theMonth,"yyyy")#" cfsqltype="CF_SQL_TIMESTAMP"> 
    AND    technician_id = <CFQUERYPARAM Value="#techID#">
</cfquery>

当我将查询更改为此时,它会以某种方式破坏我的CFChart。我的屏幕上没有任何CFErrors,但我的CFChart是空白的。

我已将其缩小为与我的查询中的相关内容:

#dateFormat(theMonth,"yyyy")#" cfsqltype="CF_SQL_TIMESTAMP"

当我删除查询的参数化部分并放入

#dateFormat(theMonth,"yyyy")#

它有效。

任何人都可以对此有所了解吗?

3 个答案:

答案 0 :(得分:4)

  

我在屏幕上没有得到任何CFErrors,但我的CFChart是空白的。

暂时忽略correct approach,发生的原因是您使用了不正确的cfsqltype参数。因此,您实际上是在向数据库发送不同的值(因此执行不同的比较),而不是您想到的。因此,查询无法找到任何匹配的记录。这就是为什么你的图表是空白的。

使用cf_sql_timestamp,您正在转换&#34;值&#34;到完整的日期/时间对象。但是,YEAR()仅返回一个四位数字。所以你要比较苹果和橘子。从概念上讲,您的查询实际上是这样做的:

  WHERE  2014 = {ts '2009-02-13 23:31:30'}

不抛出错误的原因是日期/时间值在内部存储为数字。所以你实际上是将一小部分(即年份)与一个非常大的数字(即日期/时间)进行比较。显然日期值会大得多,所以它几乎永远不会匹配年份数。同样,概念上您的查询正在执行此操作:

 WHERE 2014 = 1234567890

由于cfsqltype是可选的,很多人认为它不是很重要 - 但确实如此。

  • 验证:除了其他好处之外,cfqueryparam还根据cfsqltype(日期,日期和时间)验证提供的&#34;值&#34;数字,等等。在将SQL发送到数据库之前发生。因此,如果输入无效,则不会浪费数据库调用。如果省略cfsqltype,或者只使用默认的ie字符串,则会失去额外的验证。

  • 准确性选择正确的cfsqltype可确保您将正确的值发送到数据库。如上所述,使用错误的类型会导致CF向数据库发送错误的值。

    cfsqltype还确保以非模糊格式将值提交给数据库,数据库将以您期望的方式解释。从技术上讲,您可以将所有内容发送到数据库中。但是,这会强制数据库执行implicit conversion(通常是不合需要的)。

    使用隐式转换,字符串的解释完全取决于数据库 - 它可能并不总能得出您期望的答案。将日期作为字符串而不是日期对象提交是一个很好的例子。当前数据库将如何解释日期字符串,如&#34; 05/04 / 2014&#34;? 4月5日还是5月4日?这取决于。更改数据库或数据库设置,结果可能完全不同。

确保一致结果的唯一方法是指定适当的cfsqltype。它应该与比较列/函数的数据类型匹配,或者至少与等效类型匹配。在YEAR()的情况下,它返回一个四位数字。因此,您应该使用cf_sql_integer作为Adrian mentioned the comments。这同样适用于您的MONTH()比较。

 WHERE Year(ColumnName) = <cfqueryparam value="2014" cfsqltye="CF_SQL_INTEGER">
 AND   Month(ColumnName) = <cfqueryparam value="11" cfsqltye="CF_SQL_INTEGER"> 

现在说了所有这些,Dan's suggestion是进行日期比较的更好方法。 That paradigm更具索引友好性,无论您的目标列是包含日期(仅限)还是日期和时间,它都可以正常工作。请注意在他的示例中使用cf_sql_date

  • cf_sql_timestamp - 发送日期和时间
  • cf_sql_date - 仅发送日期。时间值被截断

答案 1 :(得分:3)

我建议你改变你的做法。从

开始
StartDate = CreateDate(TheYearYouWant, TheMonthYouWant, 1);
EndDate = DateAdd("m", 1, StartDate);

并且您的查询的日期过滤变为:

where closed_date >= <cfqueryparam cfsqltype="cf_sql_date" value="#StartDate#">
and closed_date < <cfqueryparam cfsqltype="cf_sql_date" value="#EndDate#">

这比使用where子句中的函数执行得更快。

答案 2 :(得分:2)

最好将它参数化为查询中的每个变量。

包括cfsqltype以及值。

<cfquery name="total" datasource="#datasource#">          
    select *
    from closed_tickets
    where MONTH(closed_date) = <cfqueryparam cfsqltype="cf_sql_integer" value="#month#">
          AND YEAR(closed_date) = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#dateFormat(theMonth,"yyyy")#" > 
          AND technician_id = <cfqueryparam cfsqltype="cf_sql_integer" value="#techID#">
</cfquery>

CF_SQL_VARCHAR可能会起作用,也可能不起作用,具体取决于日期的实际存储方式(日期类型或var char)。