2014-11-02 71 views
1

由于不寻常的代码设置,而不是使用cfparary与cfparam标记,而是构建一个sqlInsertCols列表和一个sqlInsertValues列表并在插入语句中使用这些列表。代码是这样的:如何将日期从coldfusion变量插入到sql字段?

<cfscript> 
    var sqlInsertCols = ""; 
    var sqlInsertValues = ""; 
    // some looping and other processing here to fill the lists 
    ... 
</cfscript> 

<cfquery datasource="..." name="insert"> 
    INSERT INTO MyTable(#sqlInsertACols#) 
    VALUES (#sqlInsertVals#) 
</cfquery> 

首先,是否有任何这方面的安全问题,考虑到双方的SQL字符串此代码中填充,而不是基于任何用户输入?

而这已经适用于我插入的几个领域,但我只是试图添加一个日期字段,无法让插入工作。日期格式为“mm/dd/yyyy”。代码中加入日期SQL名单:

sqlInsertCols = ListAppend(sqlInsertCols, "MyDateField"); 
sqlInsertValues = ListAppend(sqlInsertValues, myDateVar); 

这没有错误的运行,但在数据库中的值是1900-01-01 00:00:00.000

我试着在日期周围添加引号,但似乎无法让它正确插入。有什么办法可以做到这一点?

+0

尝试'sqlInsertValues = ListAppend(sqlInsertValues,CreateODBCDateTime(myDateVar));'。 – xpa1492 2014-11-03 03:36:28

+0

@ xpa1492 - 工作!谢谢!如果您将其作为答案发布,我会接受它 – froadie 2014-11-03 08:34:39

+0

比@ xpa1492的建议效率稍高于首先创建日期变量,而不是随后转换的字符串变量。 – 2014-11-03 13:13:35

回答

1

SQL Sever在日期周围使用单引号。你尝试过那些吗?

+0

我试过了,但是CF好像在insert语句中将它们翻译为双引号,然后它会导致错误。 – froadie 2014-11-03 08:21:58

+0

@froadie:你需要使用'preserveSingleQuotes()'函数。 – 2014-11-03 13:39:19

+0

* SQL Sever在日期周围使用单引号*不完全。引号是字符串文字所必需的。在这种情况下是日期字符串。根据目标列,该字符串*可*被隐式转换为'date/time',但它仍然是一个字符串。 @froadie - 引号加倍的原因是CF的安全功能。不使用cfqueryparam的查询处于sql注入的风险中,所以CF会自动加倍引号以防止这种情况发生。 'preserveSingleQuotes'反转了这种行为,但是这样做会将你的db暴露给CF试图阻止**的东西。所以谨慎使用它。 – Leigh 2014-11-03 13:59:23

1

首先让我说,我根本不喜欢这种方法。看起来你正在尝试使用cfquery作为通用包装 - 一种“插入”变量列表的方式。这会让您的查询被其他代码遮蔽。通过查看查询是最容易受到攻击的向量,更不用说通常包含用户输入,这使得查询变得更加困难。此外,CFQUERY是CF语言的强度 - 你可以剪切和从DB IDE和变化的可变投入简单(当然增加的cfqueryparam)粘贴几种语言之一。

最后,您的查询需要cfqueryparam来保护SQLi - 所以在回答您问题的最后部分时 - 是的,这段代码很脆弱。如果不使用cfqueryparam,很少有情况。

所以......这里有一个解决方案(同样,我不喜欢或推荐:),你可以作为一个起点使用:

<cfscript> 
    var sqlInsertCols = ""; 
    var sqlInsertValues = ""; 
    // some looping and other processing here to fill the lists 
    ... 
</cfscript> 

<cfquery datasource="..." name="insert"> 
    INSERT INTO MyTable(#sqlInsertACols#) 
    VALUES (
    <cfloop list="#sqlinsertValues#" index="colVal"> 
     <cfif isDate(colVal)> 
      <Cfqueryparam cfsqltype="CF_SQL_DATE" value="#colval#"/> 
     <cfelse> 
      <cfqueryparam cfsqltype="CF_SQL_CHAR" value="#colval#"/> 
     </cfif> 
    <cfif colVal IS NOT listlast(sqlInsertValues)> 
       , 
     </cfif> 
    </cfloop> 

    ) 
</cfquery> 

这假定确定为日期字段被插入类型为“日期”的DB中的列中。它还假定所有“其他”非日期字段都是字符字段。您可能需要为数字或整数或数据中的任何内容添加检查。

此外,如果你需要核对值的列名,你可以使用listgetat如下:

<cfscript> 
    var sqlInsertCols = ""; 
    var sqlInsertValues = ""; 
    // some looping and other processing here to fill the lists 
    ... 
</cfscript> 

<cfquery datasource="..." name="insert"> 
    INSERT INTO MyTable(#sqlInsertACols#) 
    VALUES (
    <cfloop from="1" to="#listlen(sqlinsertValues)#" index="x"> 
     <cfif listgetat(sqlInsertCols,x) IS 'dateadded'> 
      <Cfqueryparam cfsqltype="CF_SQL_DATE" value="#listgetat(sqlInsertValues,x)#"/> 
     <cfelseif listgetat(sqlInsertCols,x) IS 'userid'>> 
      <cfqueryparam cfsqltype="CF_SQL_INTEGER" value="#listgetat(sqlInsertValues,x)#"/> 
     </cfif> 

     <cfif x IS NOT listlen(sqlInsertValues)> 
      , 
      </cfif> 

    </cfloop> 
    ) 
</cfquery> 

最后,完全不建议快速和肮脏解决方案,你可以试试这个:

<cfscript> 
    var sqlInsertCols = ""; 
    var sqlInsertValues = ""; 
    // some looping and other processing here to fill the lists 
    ... 
</cfscript> 

<cfquery datasource="..." name="insert"> 
    INSERT INTO MyTable(#sqlInsertACols#) 
    VALUES (
    <cfloop list="#sqlinsertValues#" index="colVal"> 

     '#colval#' 
      <cfif colVal IS NOT listlast(sqlInsertValues)> 
        , 
      </cfif> 
    </cfloop> 

    ) 
</cfquery> 

这可能是因为您的RDBMS隐式转换 - 它可以从字符转换为日期,int或数字在许多/大多数情况下。当然你可能会轻易得到一个语法错误。

最后请注意:上述第一和第三个样品用一些简单的方法来插入列表中的逗号 - 比较值在列表中的最后一个值和插入,如果他们不匹配。所以这个假设未来任何项目没有持续列表是不一样的,在列表中的最后一项。如果最后一项在您的查询中重复出现,那么您将得到一个缺少逗号的语法错误。祝你好运!

ERRATA: 仅供参考 - 在最后一个片段中 - 单引号外变量不会被CFQUERY转义..所以当您使用'#varName#'时 - 单引号将被保留,但是当它们位于变量内时它们会被转义 - 因为CF自然会认为(并且最佳实践是指示)您正在处理要以可变形式插入的内容,而不是查询语言本身。

+0

感谢您的详细解答。其中一些非常有用。我将重构我在某种程度上的做法(我将为列名提供一种“lookup”结构,这样我就可以根据html来获取它,但仍然可以控制它)。我可能会在循环中使用cfqueryparams。 – froadie 2014-11-05 08:36:25

相关问题