Vertx Mysql Client prepareQuery with in statement - java

I am trying to execute query with vertx with in sql statement and I am failing to make it work. I don't understand how should I pass a collection of values
here is what I am trying to do:
MySQLConnectOptions connectOptions = new MySQLConnectOptions()
.setPort(3306)
.setHost("localhost")
.setDatabase("innodb")
.setUser("root")
.setPassword("local1234");
MySQLPool sqlPool = MySQLPool.pool(connectOptions, new PoolOptions());
PreparedQuery<RowSet<Row>> prepare = sqlPool.preparedQuery(
"select * from myTable where someId in (?)");
List<String> ids = List.of("someUniqueId", "other");
Future<RowSet<Row>> execute = prepare.execute(Tuple.of(ids));
execute.onComplete(
rows -> System.out.println(rows.result().size())
);
When running with one value without the in (?) it is working fine
any ideas?

These two queries are different:
select * from myTable where someId in ('123','456','789')
select * from myTable where someId in ('123,456,789')
The first query has a list of three discrete values. The second query has one value, a string that happens to contain commas.
A parameter can only be used to substitute for a scalar value. So when you pass a string with commas as the value, it is as if you executed the second query I showed.
To get the result you want, you need multiple parameter placeholders:
select * from myTable where someId in (?, ?, ?)
Use as many placeholders as the number of elements in the tuple.

Related

How to use nested SELECT statements with IN operator in SQL (JPA)?

I want to use the following SQL query in my java class:
SELECT *
FROM table1
WHERE attribute1 IN (
SELECT attribute1
FROM table2
WHERE attribute2 = c
)
Here table1 and table2 are two entities having the common column attribute1.
How to get the result of this query as a List of type table1?
You cannot get the result as List of type table1.
A table is a collection of columns. A Java List can contain only a collection of one column.
Imagine table1 contains 5 columns of different data types (say INTEGER, VARCHAR2, INTEGER, VARCHAR2, VARCHAR2). Your query will return a ResultSet containing all these values.
Now, you are expecting a simple List to store all these values. It is not correct.
If you want to store all values of a particular column, then you can do it as shown below.
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM table1 WHERE attribute1 IN (SELECT attribute1 FROM table2 WHERE attribute2 = c)");
List<String> attr = new ArrayList<String>();
while (rs.next()) {
attr.add(rs.getString("attribute1"));
}
If you wish to obtain values of different column, then use rs.getXXX("<column_name"); to fetch its details. Note: Replace getXXX with appropriate method based on datatype of the column. For example, getString() for VARCHAR, getInt() for INTEGER etc.

reuse sql param when not using named parameters

I have a query that gets called with JdbcTemplate but only one param is getting sent and I need to use that one param in two where conditions.
The Query
String sql = "select * from employee where salary > ? and netpay > ?";
The Call
The param here is only one. I.E. if the id is TEST123 the query needs to be
select * from employee where id = TEST123 and name = TEST123 even though one param is getting passed.
getJdbcTemplate().query(sql, new Object[]{"TEST123"}, CustomResultSetExtractor());
Is there any way to do this from the query side instead of passing two params?
NOTE
I do not have access to change the way the query is called, hence I cannot add named params, or just pass an additional parameter.
Use NamedParameterJdbcTemplate, a JdbcTemplate wrapper:
Template class with a basic set of JDBC operations, allowing the use of named parameters rather than traditional '?' placeholders.
This class delegates to a wrapped JdbcTemplate once the substitution from named parameters to JDBC style '?' placeholders is done at execution time.
Your SQL will be with 1 parameter:
select * from employee where id = (:id) and name = (:id)
And code will be :
MapSqlParameterSource args = new MapSqlParameterSource();
args.addValue("id", TEST123);
return new NamedParameterJdbcTemplate(getJdbcTemplate()).query(sql , args, youRowMapper);
If you can't change it, you can change your query to:
select * from employee where id = ? and id = name
I am amazed that you didn't find:
String sql = "select * from employee where id = ? and name = id";
Or did you mean or instead of and?
String sql = "select * from employee where ? in (id, name)";
I would suggest something else, you can repeat your param in Object array for example if your query have two ? then generate the parameters like so :
String param = "TEST123";
Object[] params = IntStream.range(0, 2)
.mapToObj(i -> param)
.toArray();
This will generate an array which hold two time TEST123 :
[TEST123, TEST123]
Then Just send the Object array to your code like you do.
getJdbcTemplate().query(sql, params, CustomResultSetExtractor());
If you don't know the number of hold or parameters in your query you can count them like so :
int numberOfHold = sql.length() - sql.replaceAll("\\?", "").length();

How to assign a value to the MySQL statement with the in keyword in Java?

The parameters to be passed are the int type and the quantity is uncertain.
How can I pass all the parameters at once in the case of uncertain parameters?
String SQL = "select * from table where enterprise_id in (?,?,?)";
int a,b,c = 1,2,3;//uncertain quantity
this.server.findBySql(SQL,a,b,c);
Is there a good way to avoid traversing parameters and splicing the query statements?
I think the easiest way is to pass a list is to use
org.springframework.jdbc.core.namedparam.MapSqlParameterSource.MapSqlParameterSource() which can take any type of argument for a prepared statement.
So, in your case, you can modify your SQL like this to take list parameter:
String sql = "select * from table where enterprise_id in (:listOfInt)";.
Then add the list as parameter:
MapSqlParameterSource sqlParams = new MapSqlParameterSource();
sqlParams.addValue("listOfInt", Arrays.asList(1,2,3));
Pass it to the org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate instance to execute the query like this,
this.namedParameterJdbcTemplate.queryForList(sql, sqlParams);
Which gives you a resultset, further this assumes that you have created an instance of NamedParameterJdbcTemplate at the class level.
I'am not a Java dev, but you shall pass an array parameter to an IN SQL statement:
String SQL = "select * from table where enterprise_id in (?)";
int[] array = {1, 2, 3};//uncertain quantity
this.server.findBySql(SQL, array);
please see How to use an arraylist as a prepared statement parameter for the right way to do this.
Be carefull, if your array may be very large (I mean, very very large), you better have to insert it into a temporary table using a bulk insert and then to use a JOIN statement (but only if you may reach the MySQL IN limits).
We can definitely pass array of type int to stored procs, but not sure about statements.
However we can get away with workaround like this.
Let's say int values are coming from int[] arrData.
StringBuffer arguments= new StringBuffer();
for(Integer value:arrData){
if(arguments.toString().length!=0)
arguments.append(",");
arguments.append(""+value+"");
}
and then finally pass comma separated values as input like this.
String SQL = "select * from table where enterprise_id in (?)";
this.server.findBySql(SQL,arguments.toString());

Cassandra-Java-driver : com.datastax.driver.core.exceptions.InvalidTypeException: Invalid type, column is a list but class java.lang.String provided

I have a User Defined Type in Cassandra which I created using following syntax in CQLSH :
CREATE TYPE order_items (
qty int,
name text,
milk_type text,
size text,
price decimal
);
Now in my table, I am storing a list of the type "order_items" so I can store multiple items for one object.
Something like this :
CREATE TABLE order (
order_id uuid PRIMARY KEY,
amount decimal,
location text,
items list<frozen<order_items>>,
status text,
message text
);
If I want to store a record using CQLSH, I can do so with the following syntax,
INSERT INTO order (order_id,amount,location,items,status,message) VALUES
(e7ae5cf3-d358-4d99-b900-85902fda9bb0, 5, 'San Jose',[{qty:2,name:'mocha',milk_type:'whole',size:'small',price:2.5}], 'PLACED','order is in process');
but when I try to do the same using the DataStax Java driver for cassandra, I am not able to provide the user defined type as a list of objects. I could only come up with a string syntax, but obviously it is throwing the above error.
I have tried referring the datastax documentation, but apparently it is still a work in progress : http://docs.datastax.com/en/developer/java-driver/3.1/manual/udts/
Here is my Java syntax:
session.execute(insertorderPstmt.bind(UUID.randomUUID(),new BigDecimal("4"),"Santa Clara","[{qty:2,name:'mocha',milk_type:'whole',size:'small',price:2.5}]","PLACED","in process"));
and the error:
Exception in thread "main" com.datastax.driver.core.exceptions.InvalidTypeException: Invalid type for value 3, column is a list but class java.lang.String provided
Is there anyone who has been able to store custom type lists using java driver?
Your insert query is not correct.
If you use single quote then use it for everything, and separate all field with coma. If the field is string then enclose it with quote,
Use the below insert query :
INSERT INTO order (
order_id,
amount,
location,
items,
status,
message
) VALUES (
e7ae5cf3-d358-4d99-b900-85902fda9bb0,
5,
'San Jose',
[
{qty:2, name:'mocha', milk_type:'whole', size:'small', price:2.5}
],
'PLACED',
'order is in process'
);
Using Java Driver :
Though you are inserting User define Type(UDT) value, you have create a custom codec or insert value using json or UDTValue
Here is how you can insert value through UDTValue :
//First get your UserType from cluster object
UserType oderItemType = cluster.getMetadata()
.getKeyspace(session.getLoggedKeyspace())
.getUserType("order_items");
//Now you can create a UDTValue from your UserType order_items and set value
UDTValue oderItem = oderItemType.newValue()
.setInt("qty", 2)
.setString("name", "mocha")
.setString("milk_type", "whole")
.setString("size", "small")
.setDecimal("price", new BigDecimal(2.5));
// Though you define UDT of List Let's create a list and put the value
List<UDTValue> orders = new ArrayList<>();
orders.add(oderItem);
Now you can insert data like below :
//Let your prepared statment be like
PreparedStatement insertorderPstmt = session.prepare("insert into order(order_id,amount,location,items,status,message) values(?, ?, ?, ?, ?, ?)");
//Now you can bind the value and execute query
session.execute(insertorderPstmt.bind(UUID.randomUUID(), new BigDecimal("4"), "Santa Clara", orders, "PLACED", "in process"));

create trigger for copying data from one table to dynamically generated table in postgresql

I have to simply copy data from one table to dynamically generated table. I created trigger for that..
CREATE OR REPLACE FUNCTION historylogfunc() RETURNS TRIGGER AS $example_table$
DECLARE last_device_id text;
BEGIN
PERFORM last_device_id = device_id FROM company ORDER BY id DESC LIMIT 1;
INSERT INTO "device_id"(emp_id, entry_date, name) VALUES (new.id, current_timestamp, new.name);
RETURN NEW;
END;
$example_table$ LANGUAGE plpgsql;
PERFORM last_device_id = device_id FROM company ORDER BY id DESC LIMIT 1;
It will select last device_id from table and store in var last device_id.
Suppose device_id = dv001,
I have to copy data from main table to new table i.e. dv001.
the error show: relation "device_id" does not exist.
Please help me...
I see two problems with your function:
PERFORM last_device_id = device_id FROM company ORDER BY id DESC LIMIT 1;
This is identical to SELECT last_device_id = device_id FROM company ...;, except that the result is discarded.
So this statement does nothing since it has no side effects. That cannot be intended.
The (discarded) result of SELECT last_device_id = device_id ... is the boolean result of the comparison operator =. Is that what you intended?
INSERT INTO "device_id"(emp_id, entry_date, name) VALUES (new.id, current_timestamp, new.name);
This causes the error message, because there is no table called device_id. Are you sure that there is a table of this name? Then maybe you have to qualify it with a schema name, if it is not in the search_path.
But device_id looks more like a column name than a table name to me.
In the light of your comments below:
If you want to INSERT into a table whose name is the latest device_id entry in company, you'll have to use dynamic SQL like the following:
SELECT device_id INTO last_device_id
FROM company
ORDER BY id DESC
LIMIT 1;
EXECUTE 'INSERT INTO ' || quote_ident(last_device_id)
|| ' (emp_id, entry_date, name) VALUES ($1, $2, $3)'
USING new.id, current_timestamp, new.name;

Categories