2016-10-18 52 views
0

我有一些文本文件,我必须在SQL中的一个表中插入。我有我的文本文件名称存储在单独的表。我必须从该表中获取名称,然后使用fileOpen()从特定文件夹获取文件。完成该步骤后,我有问题要决定什么是执行下一步的最佳方法。所以我必须使用fileReadLine()来获取每个文本文件行的上下文。此外,我不应该读第一行,因为它只包含列名。第二,我必须检查一次,我打到文件的结尾。在最后我必须循环并在表格中执行INSERT。我想知道是否有任何新的方法来做到这一点?我目前的代码有两个cfloops,看起来效率很低。这里是我当前的代码:使用ColdFusion和SQL插入文本文件的最佳方法?

<!--- 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> 

我在想这样做单独的循环,将创建数组应插入,然后运行另一个循环做插入的所有元素。我不确定这种情况下最好的方法是什么。如果有人知道任何其他方式,请让我知道。由于

+4

大多数数据库都有工具来加载文本文件,这通常比循环更有效。这些工具是DBMS特有的。在MySQL上进行搜索 - LOAD DATA,SQL Server - BULK INSERT等。有很多例子。 (顺便说一句,有数据库问题,总是包括你的DBMS和版本。) – Leigh

回答

2

你也可以遍历文件系直接像这样:

<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> 

这将是一个单一的循环。根据文件的大小,它可能会或可能不会更有效。此外,通常还会检查类型,空值,空字符串 - 类似的东西。所以你可能在插入之前有一些数据按摩代码。希望这可以帮助。

+1

很好的与''搭档'我没有想到这一点。 ('ListLen()'检查会很好,因为这会因为某些原因列数太少而被炸掉) – Tomalak

+0

@MarkAKruger我还有几个问题与上面的答案有关。我应该删除我的Replace()代码?这是否已经在你的代码中完成了一些?此外使用listgetAt()我基本上只是指定我需要从我的文件中的元素的位置?或者我不明白这是如何工作的......我也应该将INSERT INTO ...部分移出cfloop,并将该循环放在VALUES之后?我认为这可能是更好的选择,但不能确定100%? –

+0

我正在测试listGetAt(),它将指定位置,但我仍然在列名的第一行。我如何摆脱我的.txt文件的第一行?提前致谢。 –

1

如果要将100,000个值插入表中,则无法提供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 *。命名您需要的列。
  • 不要评论显而易见。 “从文件表中获取东西”是一个完全多余的评论,代码表示这一点。
  • 使用适当的变量名称。 filesmyQuery1好得多。
  • 有没有必要使用##除非你想插入变量内容到一个字符串,CF标签属性或输出。

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

  • 总是在您的查询中使用<cfqueryparam>。这样你就不用担心值中的引号。这种方法在循环中效率更高。
  • INSERT查询不真的需要一个name
  • 避免<cftry>没有<cfcatch>除非你真的不在乎错误。
  • 最后但并非最不重要的:CSV是一种比人们想象的更为复杂的格式。当TAB或NEWLINE由于某种原因(如果该值被引用时这将是有效的)成为该值的一部分时,“在TAB字符处将其按行分割”将不起作用。四处寻找一个CSV解析器(也许开始here)。
相关问题