ON DUPLICATE KEY UPDATE的Prepared Statement语法(参数数量错误)

6

我要做的是将数据插入到这个表中,如果主键(entity_id)存在,则更新记录。但是我遇到了SQL语法的问题。当我想在 'VALUES' 后面添加更多参数时,它不允许我这样做,因此我会得到以下错误:

参数索引超出范围(7 > 参数数目,即 6)。

int insertOrUpdateSuccess = MyDBSyncher.UPDATE("INSERT INTO " + DB_NAME + ".entities " +
    "(`entity_id`, `wai_type`, `wai_id`, `character_id`, `looted`, `creation_time`) " +
    "VALUES ((?), (?), (?), (?), (?), (?)) " +
    "ON DUPLICATE KEY UPDATE " +
    "`wai_type`='(?)', `wai_id`='(?)', `character_id`='(?)', `looted`='(?)'", 
    new String[]{tmpEntityId, values[0], values[1], values[2], values[3], values[4],
    values[0], values[1], values[2], values[3]});

这里有一个类似的问题 (链接),但我无法根据我的需求进行解释。很抱歉可能会发布重复内容。

这是我代码中的UPDATE()函数:

public static int UPDATE(String updateStatement, String[] params){
    try {
        if(!conn.isClosed()) {
            logger.trace("Successfully connected to MySQL server using TCP/IP - " + conn);

            stat = conn.prepareStatement(updateStatement);
            for (int i = 0; i < params.length; i++){
                stat.setString(i+1, params[i]);
            }
            return stat.executeUpdate();
        }
    } catch(SQLException eSQL) {
        logger.fatal(eSQL.getMessage());
    }
    return -1;
}

感谢您对此的任何帮助。 :)

1
你不想在 ? 周围加上 ' 引号,我注意到这是你在前六个参数后面所拥有的。也许这就是问题所在。 - Sotirios Delimanolis
2个回答

33

为什么不直接消除在重复的值中放置绑定参数,如下查询:

INSERT INTO mytable (col1, col2, col3) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE col1=?, col2=?, col3=?;

可以改写为:

INSERT INTO mytable (col1, col2, col3) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE col1=VALUES(col1), col2=VALUES(col2), col3=VALUES(col3);

我认为应该更喜欢第二种而不是第一种,因为:

  • 在查询的'ON DUPLICATE KEY UPDATE'部分中不使用绑定参数意味着您不必编写额外的代码(或在某些情况下进行迭代)来绑定它们

  • 编写较少的代码意味着出现绑定错误(例如打字错误等)的机会更少

  • 它具有更好的可读性


1
我不明白这样做有什么好处。它确实更冗长,但也没有考虑到我原来的问题周围的任何内容(为什么引号不起作用,或者任何动态值相关的问题)。 - KisnardOnline
1
@JayAvon 首先,它完美支持动态值,即在重复插入的情况下,我的答案中的语句将给您完全相同的结果。 话虽如此,应该优先选择第二个而不是第一个,因为它会带来以下好处:
  • 由于您不再使用绑定参数来进行“ON DUPLICATE KEY UPDATE”部分,因此您无需编写额外的代码(或在您的情况下进行迭代)来绑定它们
  • 编写更少的代码意味着更少出现绑定错误(例如拼写错误等)
  • 此外,正如您已经发现的那样,它具有更好的可读性
- sactiw

5
PreparedStatement的上下文中,字符?是一个绑定参数,稍后将被某个值(使用setter)替换。如果在引号内使用它,则该语句会将其视为文字,而不是要替换的内容。你查询的这部分内容如下:
"`wai_type`='(?)', `wai_id`='(?)', `character_id`='(?)', `looted`='(?)'", 

wai_type设置为(?),这不是您想要的。去掉单引号。实际上,也要去掉`字符。


1
+1 是因为 '(?)' 会被视为字符串字面量而不是绑定参数,所以无法正常工作。 - sactiw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接