【问题标题】:Create a generic PreparedStatement method to check if value does exist in a Table创建一个通用的 PreparedStatement 方法来检查表中是否存在值
【发布时间】:2019-04-20 16:41:03
【问题描述】:

我想创建一个通用的 PreparedStatement 方法。 我有几个任何原始数据类型的值,以及一个特定查询(SELECT COUNT(1) FROM TABLE WHERE COLUMN = ?),甚至有两个或更多具有相同查询的值(SELECT COUNT(1) FROM TABLE WHERE COLUMN = ? AND COLUMN1 = ?) 要知道它是否存在,这些查询甚至可能来自任何连接/数据库。

我现在遇到的问题是,我必须为每个值/查询创建一个新方法,并且我想创建一个唯一/最少的方法来检查它。

Examples:
Check if 1, does exist in SELECT COUNT(1) FROM TABLE1, in database1
Check if "Hey", does exist SELECT COUNT(1) FROM TABLE1 in database1
Check if "Hey" and 2, does exist SELECT COUNT(1) FROM TABLE2 in database1
Check if "TEST-001-TEST", does exist SELECT COUNT(1) FROM TABLE1 in database2

Or Basically:
Check if any primitive data type, and any number values does exist in an specific query, in any connection/DB using PreparedStatement
...

【问题讨论】:

标签: java sql oracle prepared-statement exists


【解决方案1】:

首先,让我强调一下,我认为您应该为此使用一些经过测试的库。构建动态 SQL 是有风险的,如果您从用户提供的数据构建 SQL,您可能很容易对 SQL 注入敞开心扉。

Elliot Frisch 链接的answer 包含不错的选项。

现在,这些查询构建器在后台所做的实际上是根据您提供的数据构建一个 SQL 字符串。当然也可以自己做。基本上,您构建一个方法,该方法采用表名、列名列表和值列表。

然后构建 SQL 字符串

StringBuilder sql = new StringBuilder();
sql.Append("SELECT 1 FROM ");
sql.Append(QuoteTableName(tableName));
sql.Append(" WHERE ");
bool firstCol = true;
for(String col: columns) {
   if(firstCol) {
      firstCol = false;
   } else {
      sql.Append(" AND ");
   }    
   sql.Append(QuoteColumnName(col));
   sql.Append(" = ?");    
}

现在您可以创建准备好的语句并绑定参数值。 PreparedStatement.setObject 在大多数情况下适用于大多数原始值。如果遇到类型转换问题,可以为SQLType添加单独的参数。

PreparedStatement stmt = connection.prepareStatement(sql.toString());
for(int i = 0; i < values.length; ++i) {
   Object val = values[i];
   stmt.setObject(i+1, val);
}

这里的棘手部分是引用表名和列名。这在数据库之间会有所不同,据我所知,JDBC 没有万无一失的方法。 如果有人能纠正我,我会很高兴。

【讨论】:

  • 这确实有助于设置 SQL,但问题是我已经知道/有查询。我有值/值、检查它是否存在的查询以及数据库。问题是如何动态构建准备好的语句。 (何时对每个值使用 .setInt、.setString、.setString 以及使用次数等)。
  • @TestingTheTest 我添加了一个如何使用setObject 方法的示例。在我的测试中,这可以正常工作,但这取决于驱动程序。
  • 我最终使用了 setObject 并将对象列表作为参数和查询本身。
【解决方案2】:

我用 Java 编写了一种(当然是动态的)脚本语言,它具有 SQL 功能。看看这些相关的代码 sn-ps 看看它们是否对你有帮助:

https://github.com/EngineHub/CommandHelper/blob/master/src/main/java/com/laytonsmith/core/functions/SQL.java#L173 https://github.com/EngineHub/CommandHelper/blob/master/src/main/java/com/laytonsmith/core/functions/SQL.java#L312

相关资料基本是:

要知道有多少个参数,我计算问号,但我可能应该使用 PreparedQuery.getParameterMetaData().getParameterCount()。除非硬编码的字符串中带有问号,否则两者都可以工作,但使用参数元数据需要与数据库的活动连接,这在我的情况下是不可取的。一旦您知道应该有多少个参数(使用任一方法),您就可以循环该次数,并使用各种 set*(i, value) 方法,其中 i 是 1-indexed 参数计数。您可以从 PreparedQuery.getParameterMetaData() 获得许多其他信息,包括使用 getParameterType() 获取每个参数所需的类型。但是使用参数元数据是解决您的问题的方法,您可以更深入地挖掘它以找到更多您需要的信息。

【讨论】:

  • 我可以只计算 ? 的数量,或者传递一个值列表和做preparedStatement.setObject,这样原始数据类型就无关紧要了吗?
  • PreparedStatement.getParameterMetaData().getParameterCount() 肯定是更理想的解决方案,你可以在 switch 语句中使用 getParameterType() 来确定参数应该是什么类型。
  • 但是由于我想创建一个带有值的“通用方法”,用于检查值是否在其中的 sql 和数据库,我的猜测是应该在方法中创建 PreparedStatement ,所以我无法对尚未创建的任何内容执行 getParameterCount()。
猜你喜欢
  • 2019-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-10
  • 1970-01-01
相关资源
最近更新 更多