如果两列已经存在,请插入表格

时间:2017-12-19 05:30:38

标签: java mysql

以下是我现在使用的代码,它提供了MySQL语法错误:

UUID uuid = player.getUniqueId();
    long uuid_m = uuid.getMostSignificantBits(), uuid_l = uuid.getLeastSignificantBits();
    String query = String.format(
            "INSERT INTO players (uuid_m, uuid_l, name, clan, xp, rank)" +
                    "SELECT * FROM SELECT CONCAT('%d', '%d', '%s', '%s', '%d', '%d') AS tmp" +
                    "WHERE NOT EXISTS (SELECT CONCAT(uuid_m, uuid_l) FROM players WHERE uuid_m = '%d' AND uuid_l = '%d')" +
                    "LIMIT 1;", uuid_m, uuid_l, player.getName(), "TestClan", 0, 0, uuid_m, uuid_l);

我用Java编写代码,但我尽量让它尽可能可读,但我并不认为代码中的Java本身就是特定的。我的数据库中的表被称为"玩家"它有列(uuid_m long,uuid_l long,varchar(50)name,varchar(50)clan,xp int,rank int)。我考虑过只使用varchar(32)而不是将UUID分成两部分,但我做了一些计算,并且需要4倍的空间。我对MySQL很新,但我想尝试保持一切有效。

3 个答案:

答案 0 :(得分:1)

首先,SELECT * FROM SELECT是多余的,即使它有效,我怀疑。其次,您试图在表中插入n列,但只传递1 - CONCAT会将值连接到1列。您需要删除concat并提供要在两个SELECT中插入的值的完整列表(玩家存在的地方和他不在的地方)。

答案 1 :(得分:1)

您有几个问题

  1. 在每个损坏的"行"结尾处缺少空格。例如

    "INSERT INTO players (uuid_m, uuid_l, name, clan, xp, rank)" +
                                                               ^
    "SELECT CONCAT('%d', '%d', '%s', '%s', '%d', '%d') AS tmp" +
                                                             ^
    "WHERE NOT EXISTS (SELECT CONCAT(uuid_m, uuid_l) FROM players WHERE uuid_m = '%d' AND uuid_l = '%d')" +
                                                                                                        ^
    "LIMIT 1;"
    

    在所有这些情况下,下一行""例如,...AS TMPWHERE...您需要包含空格。

  2. WHERE

  3. 之前有FROM条款
  4. 您正在动态构建查询并插入可能受污染的值,让您自己对SQL注入攻击持开放态度。请改为使用带有替换点的PreparedStatement
  5. 可能会有更多,但你应该在继续之前解决这些问题。

    诊断SQL语法错误时,请始终打印出程序构建的最终语句,以查看您传递给驱动程序的内容。

答案 2 :(得分:0)

这种方法并非必要,事实上可能有害。最简单的解决方案是将UUID指定为PRIMARY KEY并完成它:

INSERT INTO players (uuid, name, clan, xp, rank)
  VALUES (?, ?, ?, ?, ?)

这是书,它的工作原理。如果您有重复记录,插入将失败。如果您想更新现有记录,您可以撰写UPDATE ... WHERE uuid=?或使用MySQL ON DUPLICATE KEY功能," upsert"在其他数据库中:

INSERT INTO players (uuid, name, clan, xp, rank)
  VALUES (?, ?, ?, ?, ?)
  ON DUPLICATE KEY SET name=VALUES(name), clan=VALUES(clan), xp=VALUES(xp), rank=VALUES(rank)

这样,如果条目已经存在,您甚至不必费心去测试。如果它存在,它将更新您手头的任何新数据。

关于UUID字段:

你要处理多少十亿行,32个字符和8个字符的边际成本会使你的存储破产?不要过于聪明一半并将UUID存储为二进制数据,尤其是当您将其放在两个不同的列中时。这就是你在一个团队中获得糟糕声誉的方式,因为他们制作了这些荒谬的巴洛克式数据结构,每个人都讨厌使用它们。将其存储为十六进制编码的文本,其中的破折号与其他人一样。如果您的数据库平台支持本机UUID类型,如Postgres,请使用它,但仅限于。

UUID也是128位,因此您需要两个BIGINT值,最小值,或者换句话说,16个字节。我不认为你会意识到每行额外16个字节是多么无关紧要,而单一列提供的直接,易读和简单的索引优势。

我们生活在一个只有几千兆字节存储空间的驱动器被认为很小并且内存同样丰富的时代。我们不需要从数据结构中挤出一点点。这是过早优化的经典案例。只要按照传统方式进行操作,直到您具体证明该方式不适合您的特定情况,然后衡量问题的影响,以便在您尝试其他方法时可以看到它们的表现如何与基线相比。