【问题标题】:Coldfusion/Lucee - Loop over 3D array to insert into database using multiple inserts using one queryColdfusion/Lucee - 循环 3D 数组以使用一个查询使用多个插入插入数据库
【发布时间】:2017-12-24 22:55:26
【问题描述】:

我知道标题是满嘴的 - 对此感到抱歉,但在这里想具体说明一下。

数据库:MySql(技术上是 Maria)
ColdFusion(技术上是 Lucee:5.x)

数组如下所示:

注意:最外面的数组只显示 2 的一部分,并且可以持续到 30 年代。

我希望对数组执行一个循环,以使用一个查询将图像中标记为“字符串”的元素插入到数据库中。为了清晰和简洁起见,查询已被修剪:

for (outer = 1; outer <= ArrayLen(myArray); outer++) {
    local.currentrow = local.currentrow + 1;
    for (inner = 1; inner <= ArrayLen(myArray[outer]); inner++) {
            local.sql = "
                INSERT INTO table (uuid, typeID, menuId, activityID, userID)
                VALUES (
                    '#local.uuid#',
                    #myArray[outer][inner][1]#, 
                    #myArray[outer][inner][2]#,
                    #myArray[outer][inner][3]#,
                    #arguments.formDataStruct.userID#
            )";  
    queryExecute(local.sql);   
    }
}

我正在寻找沿着这条线的东西,但正如所写的那样,它不起作用:

local.sql = "
INSERT INTO table (uuid, typeID, menuId, activityID, userID)
VALUES (
    if (local.currentrow gt 1) {
        ,
    }
    for (outer = 1; outer <= ArrayLen(myArray); outer++) {
        local.currentrow = local.currentrow + 1;
        for (inner = 1; inner <= ArrayLen(myArray[outer]); inner++) {

                    '#local.uuid#',
                    '#myArray[outer][inner][1]#', 
                    '#myArray[outer][inner][2]#',
                    '#myArray[outer][inner][3]#',
                    '#arguments.formDataStruct.userID#'
        }
    })
";
queryExecute(local.sql); 

我得到的错误信息是

位置[1]的元素在数组中不存在

但如果我执行writedump[1][3][3](例如),我将得到值 24。

【问题讨论】:

  • 什么不起作用?有例外吗? MySQL 通常会打印出类似error in statement starting with... 的内容。
  • 哦,我漏掉了,不是吗。错误与 CF 相关,说明:Element at position [1] doesn't exist in array。添加了要发布的错误消息。
  • 您确定错误与该代码有关吗? myArray 在哪里定义?对我来说工作得很好,但注意到变量不像其他变量那样具有“本地”和“参数”的范围。此外,for(elem in array) 循环比from-to 循环更易读trycf.com/gist/1569556843207106fe09123cf5aac703/…
  • myArray 的范围在函数的顶部,尽管此处的原始帖子中没有显示。这是一个很好的收获。我会将该范围添加到我的数组中 - 也许这一直是问题所在。从另一个 SO 帖子中发现了从到循环的方法,所以我想我会尝试一下。仍在学习 cfscript 循环,所以我很欣赏其中的要点 - 看起来很有趣。
  • 最终,查询应该使用查询参数来保护和性能。目前,如果您遇到 SQL 错误,请使用writeDump(local.sql) 进行故障排除。将生成的 sql 复制并粘贴到 MySQL 中并运行它。 MySQL 通常提供比 CF 更有意义的错误消息。

标签: coldfusion lucee


【解决方案1】:

我建议不要在 INSERT 语句上循环,而只是在 VALUES 上循环以生成单个 INSERT 语句。单个 INSERT 将显着更快地执行,而且它将最大限度地减少与数据库的连接。

使用以下内容构建值列表:

  for (var outer in arguments.inArray) {
    for (var inner in outer) {
      // Concat elements of inner array to a SQL VALUE string. If UUID is supposed to be a unique identity for the row, use Maria's uuid() instead of CF (or skip the UUID insert and let Maria do it).
      // inArray elements and inUserID should be sanitized.
      local.values &= "( uuid(), '" & inner[1] & "','" & inner[2] & "','" & inner[3] & "'," & local.userID & ")," ;
    }
  }
  local.values = left(local.values,len(local.values)-1) ; // Get rid of the last comma.
  local.sql = "INSERT INTO table (uuid, typeID, menuId, activityID, userID) VALUES " & local.values ;

创建 SQL INSERT 字符串后,执行查询以插入记录。 (您可能会以不同的方式构建上述函数来处理构建查询字符串和参数,然后在一个地方全部执行。)

不要忘记清理您的数组和其他输入。数组是来自您控制的来源还是用户输入?

https://trycf.com/gist/7ad6af1e84906b601834b0cc5ff5a392/lucee5?theme=monokai http://dbfiddle.uk/?rdbms=mariadb_10.2&fiddle=d11f45f30723ba910c58a1e3f7a7c30b

【讨论】:

  • 我们的目标是使用一个与数据库的连接——我试图用这种方式表达这个问题,但回头再读一遍,我可以看到它需要一些改进。感谢您提供示例代码。它们干净、清晰且有据可查(听起来像粉刺霜)。我通常将参数 params 定义为变量,然后在构建 SQL 语句时引用变量(例如:typeID、:menuID、:activityID 等)。我将如何在循环中做到这一点 - 或者会有什么不同?
  • 这是我所指内容的清理示例:local.params = { menuID = { value = arguments.formStruct.menuID, cfsqltype = 'CF_SQL_INTEGER' }, typeID = { value = arguments.formStruct.typeD, cfsqltype = 'CF_SQL_INTEGER' }, userID = { value = arguments.formStruct.userID, cfsqltype = 'CF_SQL_INTEGER' } }; 然后我的执行 SQL 语句如下所示:queryExecute(local.sqlqry, local.params);
  • 数据通过下拉值来自表单,但下拉值由用户从应用程序的另一个区域提供。
  • 我找到了清理变量的位置。多么棒的练习啊,谢谢!
猜你喜欢
  • 2015-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-22
  • 2014-11-27
  • 1970-01-01
  • 2018-08-24
相关资源
最近更新 更多