Java 不再被缓存(jOOQ和Hibernate最近也通过提供解决方案解决了这一问题)
(免责声明:我为jOOQ背后的公司工作)不适用于所有数据库,但它是“正确”的方法。你指的是所有驱动程序。一些驱动程序拥有这一年(上个世纪?)标准的专有等价物。另一种方法是将一批值放入临时表中,但并非所有数据库都支持该方法。。。根据Sun的说法,阵列内容[通常]保留在服务器端,并根据需要进行拉取。PreparedStatement.setArray()可以从以前的结果集发回数组,而不是在客户端创建新数组。这对我来说不是一个真正的解决方案,因为我想发送不同数量的数组?每次我打电话给ps,但别以为我没有考虑过PAnother hack:您可以使用大量的参数占位符—尽可能多地使用最长的值列表—如果您的值列表较短,您可以重复值:…其中searchfield位于(?,,,,,,,,,,,,,,,)中,然后提供值:a,B,C,D,a,B,C,但总的来说,我支持Adam的解决方案:动态生成SQL,然后连接?与必须传递的值的数量相匹配的占位符。比尔,如果我不想重用PreparedStatement,这个解决方案是可行的。另一种解决方案是多次调用单个参数,并在客户端累积结果。构建/执行自定义数量为的新语句可能更有效?但每次都是这样。哦,我知道它不会使用indexesit。它对某些字符串不起作用,例如,如果字符串包含“,”。是的,你是对的。在本例中,我的目标是每次使用不同数量的项目重用PreparedStatement。使用“OR”会混淆意图。坚持使用“IN”,因为它更容易阅读,意图也更清楚。切换的唯一原因是查询计划不同。与一次查询一个值相比,这有什么好处?查询优化器可以通过从加载的页面检索所有可能的匹配项来减少I/O负载。表扫描或索引扫描可以执行一次,而不是每个值执行一次。插入值的开销可以通过批处理操作减少,并且可能少于几个查询。这看起来不错,但可能存在并发性问题。jdbc规范是否包含在内存中创建临时匿名表的方法?或者类似的东西,如果可能的话,不是jdbc特定于供应商的?Oscar,我认为动态生成(?,,…)是最简单的解决方法,如果您需要IN子句,但我将其留给了单独的调用,因为在我的特定情况下,性能已经足够了。准备好的语句的优点之一是,为了提高效率,可以编译一次sohuld。通过使in子句动态化,这有效地否定了准备好的语句。实际上,这对于MySQL是有效的(使用setObject将字符串数组设置为参数值)。您正在使用什么数据库?这里有一个相关的问题:不再需要使用StringBuilder了。编译器将+符号转换为StringBuilder.append(),因此不会影响性能。你自己试试:)@neu242:哦,是的,编译器使用Java 不再被缓存(jOOQ和Hibernate最近也通过提供解决方案解决了这一问题),java,security,jdbc,prepared-statement,in-clause,Java,Security,Jdbc,Prepared Statement,In Clause,(免责声明:我为jOOQ背后的公司工作)不适用于所有数据库,但它是“正确”的方法。你指的是所有驱动程序。一些驱动程序拥有这一年(上个世纪?)标准的专有等价物。另一种方法是将一批值放入临时表中,但并非所有数据库都支持该方法。。。根据Sun的说法,阵列内容[通常]保留在服务器端,并根据需要进行拉取。PreparedStatement.setArray()可以从以前的结果集发回数组,而不是在客户端创建新数组。这对我来说不是一个真正的解决方案,因为我想发送不同数量的数组?每次我打电话给ps,但别以为我没
StringBuilder
。但不是你想的那样。反编译generateQsForIn
您可以看到,每个循环迭代分配两个新的StringBuilder
,并且对每个循环调用toString
。StringBuilder
优化只捕获像“x”+i+“y”+j
这样的内容,但不能扩展到一个表达式之外。@neu242不能使用ps.setObject(1,items)
而不是在列表上迭代,然后设置参数。这段代码的哪一部分是特定于PostreSQL的?“where search_column=ANY(?)”?还是连接。createArrayOf?或者别的什么?我认为它比PostgreSQL更具体,因为.createArrayOf()
部分,但我不确定用户数组的严格语义是由JDBC规范定义的。如果.createArrayOf
不起作用,您可以自己手动创建数组文字,如String arrayLiteral=“{A,\'B\',C,D}”
(注意,“B”有空格,而C没有空格),然后statement.setString(1,arrayLiteral)
,其中准备的语句是。。。在(选择UNNEST(?::VARCHAR[])
或。。。在中(选择UNNEST(CAST(?AS VARCHAR[]))
。(注:我认为任何
都不能与选择
配合使用)伟大的解决方案!真的为我节省了时间。对于整数数组,我在createArrayOf()的第一个参数中使用了“int”,看起来不错。不过,根据文档,第一个参数似乎是特定于DB的。这似乎是最干净的解决方案。如果有人在寻找特定于HSQLDB的语法:我设法在(UNNEST(?)“NULL从不匹配任何东西”-查询中的NULL
会匹配数据库中的NULL
值吗?@CraigMcQueen不会。根据ANSI标准,Null甚至不匹配Null。您可以使用IS Null关键字匹配Null。检测联接表中不存在的行的一个好方法是将左联接与is NULL一起使用从a_a.URL=b_b.URL中的表a左联接表b中选择a.URL、b.URL,其中b.URL为NULL'这将显示表a中与表b不匹配的所有行。但要注意这一点<代码>不在
中和在
中处理空值的方式不同。运行此命令并查看发生的情况:选择“Matched”作为匹配,其中1不在(5,null)中
然后删除null
并观看魔术。或者您可以将所有额外参数设置为任何先前参数的值。任何像样的DB引擎都会过滤掉它们。因此,(1,2,3,3,3,3,3)中的a与(1,2,3)中的a相同。它也适用于不在
中,不同于不在(1,2,3,null,null,null,null)
(whi
SELECT my_column FROM my_table where search_column IN (?)
select my_column from my_table where instr(?, ','||search_column||',') > 0
ps.setString(1, ",A,B,C,");
... WHERE tab.col = ? OR tab.col = ? OR tab.col = ?
select my_column from my_table where search_column in ( SELECT value FROM MYVALUES )
while( i < param.size() ) {
ps.setString(i+1,param.get(i));
i++;
}
while( i < MAX_PARAMS ) {
ps.setNull(i+1,Types.VARCHAR);
i++;
}
public void myQuery(List<String> items, int other) {
...
String q4in = generateQsForIn(items.size());
String sql = "select * from stuff where foo in ( " + q4in + " ) and bar = ?";
PreparedStatement ps = connection.prepareStatement(sql);
int i = 1;
for (String item : items) {
ps.setString(i++, item);
}
ps.setInt(i++, other);
ResultSet rs = ps.executeQuery();
...
}
private String generateQsForIn(int numQs) {
String items = "";
for (int i = 0; i < numQs; i++) {
if (i != 0) items += ", ";
items += "?";
}
return items;
}
create or replace type split_tbl as table of varchar(32767);
/
create or replace function split
(
p_list varchar2,
p_del varchar2 := ','
) return split_tbl pipelined
is
l_idx pls_integer;
l_list varchar2(32767) := p_list;
l_value varchar2(32767);
begin
loop
l_idx := instr(l_list,p_del);
if l_idx > 0 then
pipe row(substr(l_list,1,l_idx-1));
l_list := substr(l_list,l_idx+length(p_del));
else
pipe row(l_list);
exit;
end if;
end loop;
return;
end split;
/
select * from table(split('one,two,three'))
one
two
three
select * from TABLE1 where COL1 in (select * from table(split('value1,value2')))
value1 AAA
value2 BBB
"select * from TABLE where COL in (select * from table(split(?)))"
final PreparedStatement statement = connection.prepareStatement(
"SELECT my_column FROM my_table where search_column = ANY (?)"
);
final String[] values = getValues();
statement.setArray(1, connection.createArrayOf("text", values));
try (ResultSet rs = statement.executeQuery()) {
while(rs.next()) {
// do some...
}
}
final PreparedStatement statement = connection.prepareStatement(
"SELECT my_column FROM my_table " +
"where search_column IN (SELECT * FROM unnest(?))"
);
final String[] values = getValues();
statement.setArray(1, connection.createArrayOf("text", values));
try (ResultSet rs = statement.executeQuery()) {
while(rs.next()) {
// do some...
}
}
SELECT my_column FROM my_table where search_column IN (?)
select id, name from users where id in (?, ?, ?)
preparedStatement.setString( 1, 'A');
preparedStatement.setString( 2,'B');
preparedStatement.setString( 3, 'C');
int i = 1;
for(; i <=ids.length; i++){
ps.setInt(i, ids[i-1]);
}
//set null for remaining ones
for(; i<=PARAM_SIZE;i++){
ps.setNull(i, java.sql.Types.INTEGER);
}
select * from my_table where REGEXP_LIKE (search_column, 'value1|value2')
select * from TABLE_A where ATTR IN (PARAM);
String param1 = "X";
String param2 = "Y";
String param1 = param1.append(",").append(param2);
String query = query.replaceFirst("PARAM",param1); where we have the value of query as
query = "select * from TABLE_A where ATTR IN (PARAM)";
query="select f1,f2 from t1 where f3=? and f2 in (" + sListOfIds + ");";
/*usage:
Util u = new Util(500); //500 items per bracket.
String sqlBefore = "select * from myTable where (";
List<Integer> values = new ArrayList<Integer>(Arrays.asList(1,2,4,5));
string sqlAfter = ") and foo = 'bar'";
PreparedStatement ps = u.prepareStatements(sqlBefore, values, sqlAfter, connection, "someId");
*/
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Util {
private int numValuesInClause;
public Util(int numValuesInClause) {
super();
this.numValuesInClause = numValuesInClause;
}
public int getNumValuesInClause() {
return numValuesInClause;
}
public void setNumValuesInClause(int numValuesInClause) {
this.numValuesInClause = numValuesInClause;
}
/** Split a given list into a list of lists for the given size of numValuesInClause*/
public List<List<Integer>> splitList(
List<Integer> values) {
List<List<Integer>> newList = new ArrayList<List<Integer>>();
while (values.size() > numValuesInClause) {
List<Integer> sublist = values.subList(0,numValuesInClause);
List<Integer> values2 = values.subList(numValuesInClause, values.size());
values = values2;
newList.add( sublist);
}
newList.add(values);
return newList;
}
/**
* Generates a series of split out in clause statements.
* @param sqlBefore ""select * from dual where ("
* @param values [1,2,3,4,5,6,7,8,9,10]
* @param "sqlAfter ) and id = 5"
* @return "select * from dual where (id in (1,2,3) or id in (4,5,6) or id in (7,8,9) or id in (10)"
*/
public String genInClauseSql(String sqlBefore, List<Integer> values,
String sqlAfter, String identifier)
{
List<List<Integer>> newLists = splitList(values);
String stmt = sqlBefore;
/* now generate the in clause for each list */
int j = 0; /* keep track of list:newLists index */
for (List<Integer> list : newLists) {
stmt = stmt + identifier +" in (";
StringBuilder innerBuilder = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
innerBuilder.append("?,");
}
String inClause = innerBuilder.deleteCharAt(
innerBuilder.length() - 1).toString();
stmt = stmt + inClause;
stmt = stmt + ")";
if (++j < newLists.size()) {
stmt = stmt + " OR ";
}
}
stmt = stmt + sqlAfter;
return stmt;
}
/**
* Method to convert your SQL and a list of ID into a safe prepared
* statements
*
* @throws SQLException
*/
public PreparedStatement prepareStatements(String sqlBefore,
ArrayList<Integer> values, String sqlAfter, Connection c, String identifier)
throws SQLException {
/* First split our potentially big list into lots of lists */
String stmt = genInClauseSql(sqlBefore, values, sqlAfter, identifier);
PreparedStatement ps = c.prepareStatement(stmt);
int i = 1;
for (int val : values)
{
ps.setInt(i++, val);
}
return ps;
}
}
SELECT my_column FROM my_table where search_column IN (select COLUMN_VALUE from table(?))
function getCustomers(in_customerIdList clob) return sys_refcursor is
begin
aux_in_list.parse(in_customerIdList);
open res for
select *
from customer c,
in_list v
where c.customer_id=v.token;
return res;
end;
create or replace view in_list
as
select
trim( substr (txt,
instr (txt, ',', 1, level ) + 1,
instr (txt, ',', 1, level+1)
- instr (txt, ',', 1, level) -1 ) ) as token
from (select ','||aux_in_list.getpayload||',' txt from dual)
connect by level <= length(aux_in_list.getpayload)-length(replace(aux_in_list.getpayload,',',''))+1
String inParenthesis = "(?";
for(int i = 1;i < myList.size();i++) {
inParenthesis += ", ?";
}
inParenthesis += ")";
try(PreparedStatement statement = SQLite.connection.prepareStatement(
String.format("UPDATE table SET value='WINNER' WHERE startTime=? AND name=? AND traderIdx=? AND someValue IN %s", inParenthesis))) {
int x = 1;
statement.setLong(x++, race.startTime);
statement.setString(x++, race.name);
statement.setInt(x++, traderIdx);
for(String str : race.betFair.winners) {
statement.setString(x++, str);
}
int effected = statement.executeUpdate();
}
PreparedStatement statement = connection.prepareStatement("Select * from emp where field in (?)");
Array array = statement.getConnection().createArrayOf("VARCHAR", new Object[]{"E1", "E2","E3"});
statement.setArray(1, array);
ResultSet rs = statement.executeQuery();
var s1 = " SELECT "
+ "FROM table t "
+ " where t.field in ";
var s3 = '(';
for(var i =0;i<searchTerms.length;i++)
{
if(i+1 == searchTerms.length)
{
s3 = s3+'?)';
}
else
{
s3 = s3+'?, ' ;
}
}
var query = s1+s3;
var pstmt = connection.prepareStatement(query);
for(var i =0;i<searchTerms.length;i++)
{
pstmt.setString(i+1, searchTerms[i]);
}
String query = "SELECT my_column FROM my_table where search_column IN ($searchColumns)";
query = query.replace("$searchColumns", "'A', 'B', 'C'");
Statement stmt = connection.createStatement();
boolean hasResults = stmt.execute(query);
do {
if (hasResults)
return stmt.getResultSet();
hasResults = stmt.getMoreResults();
} while (hasResults || stmt.getUpdateCount() != -1);
String baseQuery ="SELECT my_column FROM my_table where search_column IN (%s)"
String markersString = inputArray.stream().map(e -> "?").collect(joining(","));
String sqlQuery = String.format(baseSQL, markersString);
//Now create Prepared Statement and use loop to Set entries
int index=1;
for (String input : inputArray) {
preparedStatement.setString(index++, input);
}
List<String> params = getParams();
String placeHolders = String.join(",", Collections.nCopies(params.size(), "?"));
String sql = "select * from your_table where some_column in (" + placeHolders + ")";
try ( Connection connection = getConnection();
PreparedStatement ps = connection.prepareStatement(sql)) {
int i = 1;
for (String param : params) {
ps.setString(i++, param);
}
/*
* Execute query/do stuff
*/
}
select column from table
where search_column = any (string_to_array('foo,blah,abc', ',')::text[]);
select column from table
where search_column = any (string_to_array($1, ',')::text[]);
select column from table
where search_column like any (string_to_array('foo%,blah%,abc%', ',')::text[]);
public class SqlHelper
{
public static final ArrayList<String>platformList = new ArrayList<>(Arrays.asList("iOS","Android","Windows","Mac"));
public static final String testQuery = "select * from devices where platform_nm in (:PLATFORM_NAME)";
}
public class Test extends NamedParameterJdbcDaoSupport
public List<SampleModelClass> runQuery()
{
//define rowMapper to insert in object of SampleClass
final Map<String,Object> map = new HashMap<>();
map.put("PLATFORM_LIST",DeviceDataSyncQueryConstants.platformList);
return getNamedParameterJdbcTemplate().query(SqlHelper.testQuery, map, rowMapper)
}