【问题标题】:How to execute a SQL statement in Java with many values in a single variable in where in clause如何在 Java 中使用 where in 子句中的单个变量中的多个值执行 SQL 语句
【发布时间】:2014-02-28 10:38:22
【问题描述】:

我必须通过 JDBC 调用

执行下面的查询
select primaryid from data where name in ("abc", adc", "anx");

问题在子句中,我必须传递 11000 个字符串。我可以在这里使用准备好的语句吗?或任何人可以建议的任何其他解决方案。我不想为每条记录执行查询,因为它很耗时。我需要在更短的时间内运行此查询。

我正在使用 DOMParser 从 XML 文件中读取字符串。我正在使用 sql server db。

【问题讨论】:

  • 请更详细地解释这个问题。它是在创建长查询吗?
  • 你从哪里得到字符串?另一个查询或来自数据库之外的某个地方?如果我没记错的话,在准备好的语句中可以拥有的参数数量是有限制的,大约 2000 个左右。
  • 对于 oracle,限制为 1000。对于其他数据库,限制通常是查询的最大长度。如果无法从数据库查询中获得此列表,您可以将其插入临时表并加入此临时表。
  • @Vilen: 查询很简单(写有问题),但由于子句中的参数数量,它变得非常大。所以我不能写 select * from data where id in (?,?,?)。此外,值的数量不是恒定的。它因人而异。

标签: java sql sql-server jdbc prepared-statement


【解决方案1】:

我只是想知道为什么您需要手动设置 11,000 个项目,您需要在其中指定每个项目。听起来您需要将数据带入临时表 (肯定不是从 UI 中选择的..?),然后加入它以获得您想要的结果集。

【讨论】:

  • 我需要处理那 11K 条记录数据(每天都在变化),所以我需要从 db 中找到每个记录的详细信息。之前我正在为每条记录执行准备好的语句,但这需要很多时间。所以想把所有的价值观放在一起。我不知道这是否可行
  • 那 11,000 条记录一定来自数据源,对吧?听起来您需要每天将这些数据推送到数据库中,然后执行必要的联接。
  • 是的,我从许多流/单元中获取数据。这些数据我必须处理、组合并为其他流创建一个输出文件。
  • 我已经完成了一些项目,其中需要从不同的数据源聚合数据,听起来您仍然需要将它们整合到数据库中的单个源中。一旦拥有数据,这将是处理数据的最有效方式。如果您不需要出于历史目的保留该表,则可以轻松地每天截断该表。
  • 是的,对临时表执行此操作是最佳途径(尤其是在这种数据大小下)。幸运的是,大多数 RDBMS 都有批量数据加载操作,这比每次一行的插入要好得多
【解决方案2】:

使用具有 11k 字面值的 IN 子句是一个非常糟糕的主意 - 突然之间,我知道一个主要的 RDBMS (Oracle) 不支持 IN 列表中的值超过 1k。

你可以做什么:

  • 创建某种(临时)表T_NAMES 来保存您的姓名;如果您的 RDBMS 不支持“真实”(特定于会话的)临时表,则必须添加某种会话 ID
  • 用您要查找的名称填写此表
  • 修改查询以使用临时表而不是 IN 列表:select primaryid from data where name in (select name from T_NAMES where session_id = ?session_id) 或(可能更好)select primaryid from data join t_names on data.name = t_names.name and t_names.session_id = ?session_id(这里,?session_id 表示用于传递会话 ID 的绑定变量)

【讨论】:

    【解决方案3】:

    准备好的语句需要提前知道参数的数量 - 类似于:

    PreparedStatement stmt = conn.prepareStatement(
        "select id, name from users where id in (?, ?, ?)");
    stmt.setInt(1);
    stmt.setInt(2);
    stmt.setInt(3);
    

    11,000 是大量参数。使用here 所述的“批处理”方法可能是最简单的方法(总而言之-使用准备好的语句循环您的参数 每次)

    注意 - 如果您的 11,000 个字符串是早期数据库选择的结果,那么最好的方法是编写一个存储过程来在数据库中进行整个计算(避免在您的代码中来回传递 11,000 个字符串)

    【讨论】:

    • 两个选项 - 要么将 11,000 个值写入数据库中的表而不是 XML 文件(正如 JaneD 建议的那样) - 或者在循环中使用准备好的语句,例如在 500 个参数中传递一次,就像我的回答一样。 Hers 是一个更好的解决方案,但您可能无法控制创建 XML 文件的过程。
    • 所以,我必须写 '?' 500 次。这是唯一可能的方法吗?:-(
    • 使用动态sql代替prepared statement,但还是分批?因此,您仍然有一个循环将 500 个参数放入单个查询中,但是您只需构建一个字符串“WHERE IN (....)”,而不是准备好的语句。它会更慢,更不安全......但更干净的代码。
    【解决方案4】:

    您可以将所有参数字符串合并为一个以 ';' 分隔的 bitg 字符串字符

    bigStrParameter=";abc;adc;anx;"

    并使用 LOCATE 查找子字符串。

    select primaryid from data where LOCATE(concat(';',name,';'),?)>=0;
    

    【讨论】:

    • 这个查询是如何工作的,请你解释一下。我喜欢你的回答。希望这对我有用。
    • 它试图在大字符串中找到子字符串。如果名称是大合并字符串的一部分,则 LOCATE >0 返回的 chanr 索引
    • 是名称 =bigstrparameter?。定位字符串将返回 '?' 中的名称索引?我完全对你的 sql 感到困惑。
    猜你喜欢
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    • 2013-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多