使用 ColdFusion & SQL 插入文本文件的最佳方式?

Best way to insert text file using ColdFusion & SQL?

我有一些文本文件必须插入 SQL 中的 table 之一。我有单独的 table 存储我的文本文件名。我必须从 table 中获取名称,然后使用 fileOpen() 从特定文件夹中获取文件。完成该步骤后,我无法确定执行后续步骤的最佳方法。所以我必须使用 fileReadLine() 来获取每个文本文件行的上下文。另外我不应该阅读第一行,因为它只包含列名。其次,我必须在到达文件末尾时进行检查。最后,我必须循环并将 INSERT 插入 table。我想知道有没有新的方法可以做到这一点?我当前的代码有两个 cfloops,看起来效率很低。这是我当前的代码:

<!--- Grab stuff from File Table.  --->
<cfquery datasource="test" name="myQuery1">
    SELECT * 
    FROM FilesTxt
</cfquery> 

<cfloop query="myQuery1"> 
    <!--- Read File --->
    <cfset dataFile = fileOpen(here is my path&"\"&#FileName#, "read" ) /> 
    <cfset line = fileReadLine( dataFile ) />

    <!--- Loop to see if hit the end of file, if not, read next line --->
    <cfloop condition="!fileIsEOF( dataFile )">
        <cfset line = fileReadLine( dataFile ) />

        <cfif trim(line) NEQ "">
           <cfset line = #Replace(line,"'","","ALL")#>
           <cfset line = #Replace(line,'"',"","ALL")#>
           <!--- Build array of junk in the file --->
           <cfset sList = ListToArray(line, chr(9),'yes')>

           <cftry>
                <cfquery datasource="test" name="Insert">
                //Here is my Insert statement
                </cfquery>
           </cftry>
        </cfif>
    </cfloop>
</cfloop>

我正在考虑执行单独的循环,该循环将创建包含应插入的所有元素的数组,然后到 运行 另一个循环来执行插入。我不确定在这种情况下最好的方法是什么。如果有人知道任何其他方式,请告诉我。谢谢

你可以像这样直接循环文件行:

<cfloop file="**path/filename**" index="LineOfMyFile">
    <cfoutput>#LineOfMyFile#</cfoutput> 
</cfloop>

循环在文件末尾终止,因此您实际上并不需要 fileisEOF() 函数。

在循环中,您可以使用列表函数而不是遍历数组。如果您知道列表中项目的位置。像这样:

<cfloop file="**path/filename**" index="LineOfMyFile">

    <cfquery name="myinsert" datasource="#blah#">
        INSERT INTO myTable (col1, col2, col3)
        VALUES (<cfqueryparam cfsqltype="CF_SQL_INTEGER" value="#listgetat(lineOfMyFile,1,char(9))#">,
                <cfqueryparam cfsqltype="CF_SQL_CHAR" value="#listgetat(lineofmyFile,2,char(9))#">,
                <cfqueryparam cfsqltype="CF_SQL_CHAR" value="#listgetat(lineofMyFile,3,char(9))#">)
    </cfquery>

</cfloop>

这将是一个循环。根据文件的大小,它可能会或可能不会更有效。此外,通常还会检查类型、null、空字符串等。因此,您可能在插入之前有一些数据处理代码。希望这有帮助。

如果要将 100,000 个值插入 table,则无法绕过 100,000 个 INSERT 语句。

专用的数据库专有工具或命令可以以更优化的方式执行此操作,但就我个人而言,我认为这里的嵌套循环没有太大问题。

<cfquery name="files" datasource="test">
    SELECT FileName FROM FilesTxt
</cfquery> 

<cfloop query="files">
    <cfset file = fileOpen("here is my path\#FileName#", "read")>
    <cfset fileReadLine(file)>

    <cfloop condition="not fileIsEOF(file)">
        <cfloop list="#fileReadLine(file)#" delimiters="#Chr(9)#" index="item">
           <cftry>
                <cfquery datasource="test">
                    INSERT testTable (testColumn) VALUES (
                        <cfqueryparam value="#Trim(item)#" cfsqltype="CF_SQL_VARCHAR">
                    )
                </cfquery>
           </cftry>
        </cfloop>
    </cfloop>
</cfloop>

备注:

  • 不要SELECT *。命名您需要的列。
  • 不要评论显而易见的事情。 "Grab stuff from File Table" 是一个完全多余的注释,代码是这么说的。
  • 使用正确的变量名。 filesmyQuery1.
  • 好多了
  • 没有必要使用## 除非你想将变量内容插入一个字符串,插入一个CF标签属性或插入输出。

    <cfset line = #Replace(...)#>   <!--- useless use of ## --->
    <cfset line = Replace(...)>     <!--- much better --->
    
  • 您可以使用 <cfloop list=""> 循环 CSV 文件中的一行。毕竟这是一个简单的列表。

  • 始终在查询中使用 <cfqueryparam>。这样您就不必担心值中的引号。它在循环中也更有效。
  • INSERT 查询实际上并不需要 name
  • 避免 <cftry> 没有 <cfcatch> 除非你 真的 不关心错误。
  • 最后但同样重要的是:CSV 是一种比人们想象的更复杂的格式。当 TAB 或 NEWLINE 由于某种原因成为值的一部分时 "Just split it line-wise at the TAB character" 将不起作用(如果引用该值则有效)。四处寻找 CSV 解析器(也许开始 here)。

所有这些答案都是错误的。如果你想插入一堆值使用 SQL BULK INSERT

<cfset myInserts = "">
<cfloop file="test" index = "line">
   <cfset myInserts = listAppend(myInserts,"(#line#)">
</cfloop>
<cfquery>
INSERT INTO myTable VALUES #preserveSingelQuotes(myInserts)#
</cfquery>