我有一个查询,我运行以填充我试图参数化的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")#
它有效。
任何人都可以对此有所了解吗?
答案 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)。