使用 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" 是一个完全多余的注释,代码是这么说的。
- 使用正确的变量名。
files
比 myQuery1
. 好多了
没有必要使用##
除非你想将变量内容插入一个字符串,插入一个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>
我有一些文本文件必须插入 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" 是一个完全多余的注释,代码是这么说的。
- 使用正确的变量名。
files
比myQuery1
. 好多了
没有必要使用
##
除非你想将变量内容插入一个字符串,插入一个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>